diff --git a/DEPS b/DEPS
index dc79661..a0701ab 100644
--- a/DEPS
+++ b/DEPS
@@ -231,7 +231,7 @@
   # luci-go CIPD package version.
   # Make sure the revision is uploaded by infra-packagers builder.
   # https://ci.chromium.org/p/infra-internal/g/infra-packagers/console
-  'luci_go': 'git_revision:5d9b6ecf87cdfb928e1112d2838d26bc7ede2b48',
+  'luci_go': 'git_revision:be5d9aacf8987c0826223264f0427cd0b530b6a4',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -280,7 +280,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd9eeef0790b96953a58142c888b7947cb80858b9',
+  'skia_revision': '86a9562a59d654cd36a4feafee5a08b7407d7333',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -292,11 +292,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'cb0b3c682314655e80ae94bef24b0bd8b8aeb935',
+  'swiftshader_revision': 'd1116fa9e9dce90556f8db973ba42b246eb633f5',
   # 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': '7e2c12e172e644744fc2828e7000b3689537af12',
+  'pdfium_revision': 'c153a82e5bb12fb769060fc7718f7556e6a93c56',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -307,7 +307,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
-  'fuchsia_version': 'version:8.20220630.1.1',
+  'fuchsia_version': 'version:8.20220701.0.1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # 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 catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'bd235b08d6397cbdad59130a9e84e44eb2121058',
+  'catapult_revision': '0f408470862fe81fbd949d8058803ae759fcadc9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -359,7 +359,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': 'd85ad8d4193a3d0184c09b4236c9766f8e6a95cc',
+  'devtools_frontend_revision': 'b278ac410b64cec39279740d42f42070fb674e83',
   # 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.
@@ -395,7 +395,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': 'c5b7ff0089e7d437928cbe827bddea0cb1ba4656',
+  'dawn_revision': '24239fcc4786bc231eacc065eaa49fd484546984',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -929,7 +929,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'JSSu4Vtq9pLuRxzIKExbKSC1XkN6OCd7mLkeX5nWB7EC',
+          'version': 'lYZhX1u-VWgsLITQXwIxYzbrN3URNzSwPTP2iuDhPBQC',
       },
     ],
     'condition': 'checkout_android',
@@ -1151,12 +1151,12 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '13944455f2056bcbe2a888974b40eeb7da52ed0c',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'ce42313bd903e58e82e51ed2e0a5676d22395629',
       'condition': 'checkout_linux',
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6628661eba73cdb8e1ce6387837f948d0360fe48',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9af90cb59e23b16860bf32e1fd5d39865166e3ab',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1553,7 +1553,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '7bcfdf24e8e973d85a646811ddd6751e8dc8f543',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f413bdf83590b039eb4815d1b8b334ebbf2bd649',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1720,10 +1720,10 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'e58ed2132aa47ac110a4cce1763abfa34f4fa34e',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '0bf1255e9d42c27be5b45c506efe434477b2cbef',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '85f975b4f0f556927b678a5f2d45af989edf8e40',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'ed665521e4f1852c3756afc8ac46b2d59224f4b4',
+    Var('webrtc_git') + '/src.git' + '@' + '0b655cbef7c4b8b5233b6091d403b5e28d5430de',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1753,7 +1753,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'LOLBT9fx6Zp6tPJMXhgMoDZcTPCk-VSNk5gHIOchhIMC',
+          'version': 'ae24MBF5YbEEwpnfCm1dgu86m0StdnqA5BuDV09VyR4C',
         },
       ],
       'dep_type': 'cipd',
@@ -1763,7 +1763,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': '0JoR2aK22wezglgiEZQathxIbpRDITqBt6h9rwFMU7QC',
+          'version': 'n3jvsDMl43swXVzULALv9Wh0kHahqZ4VSy7_i3wO1LgC',
         },
       ],
       'dep_type': 'cipd',
@@ -1774,7 +1774,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'u6SVSv19aduMZOLqGYkCHbjhnJWwm0WimUYQs4q9mDgC',
+          'version': 'k-LraF0EyymBQiGapRFxHW3QchEFhcw8Uz1C9EaQES8C',
         },
       ],
       'dep_type': 'cipd',
@@ -1785,7 +1785,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': '1aHoSQfZbmKtsxSSw_7SIfNuMapnLQb_uHdo237FM88C',
+          'version': 'UU5Fs5VQoMBiiUttczNdC1YbiiL2dTmU0j55Lg-J-r0C',
         },
       ],
       'dep_type': 'cipd',
@@ -1796,7 +1796,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f5446186d95f214c48b294002701d0646ddf3998',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@025efee6576501cfa097514fee8205052c3366a6',
     'condition': 'checkout_src_internal',
   },
 
@@ -1837,7 +1837,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '1KlPjYt6II15oXX-Q3cd_Nt2rlILgJPXoti3xQHoMVkC',
+        'version': 'SZYZYegb8RTMDDlPu9C_mbjJtX09YslogU-BFuMyq4kC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/components/arc/BUILD.gn b/ash/components/arc/BUILD.gn
index 5eb5133..052e979 100644
--- a/ash/components/arc/BUILD.gn
+++ b/ash/components/arc/BUILD.gn
@@ -399,7 +399,6 @@
     "compat_mode/touch_mode_mouse_rewriter_unittest.cc",
     "crash_collector/arc_crash_collector_bridge_unittest.cc",
     "dark_theme/arc_dark_theme_bridge_unittest.cc",
-    "disk_quota/arc_disk_quota_bridge_unittest.cc",
     "enterprise/arc_data_remove_requested_pref_handler_unittest.cc",
     "enterprise/arc_data_snapshotd_bridge_unittest.cc",
     "enterprise/arc_data_snapshotd_manager_unittest.cc",
diff --git a/ash/components/arc/arc_features.cc b/ash/components/arc/arc_features.cc
index 9a7097c..9243802 100644
--- a/ash/components/arc/arc_features.cc
+++ b/ash/components/arc/arc_features.cc
@@ -88,6 +88,11 @@
 // Controls the size of the guest zram.
 const base::FeatureParam<int> kGuestZramSize{&kGuestZram, "size", 0};
 
+// Enables/disables mlock() of guest memory for ARCVM.
+// Often used in combination with kGuestZram.
+const base::Feature kLockGuestMemory{"ArcLockGuestMemory",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Control properties of Logd at boot time. This is only for ARCVM.
 const base::Feature kLogdConfig{"ArcGuestLogdConfig",
                                 base::FEATURE_DISABLED_BY_DEFAULT};
@@ -242,4 +247,22 @@
 const base::Feature kVmBroadcastPreNotifyANR{"ArcVmBroadcastPreAnrHandling",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// If set, enable responsive balloon sizing. Concierge will listen on a VSOCK
+// for connections from LMKD in Android. When LMKD is about to kill an App, it
+// will signal the balloon sizing code, which may deflate the balloon instead
+// of killing the app.
+const base::FeatureParam<bool> kVmBalloonPolicyResponsive{&kVmBalloonPolicy,
+                                                          "responsive", false};
+
+// The amount of time LMKD will wait for a response from concierge before
+// killing an app.
+const base::FeatureParam<int> kVmBalloonPolicyResponsiveTimeoutMs{
+    &kVmBalloonPolicy, "responsive_timeout_ms", 100};
+
+// If an app should not be killed, the balloon will be deflated by
+// min(app_size, responsive_max_deflate_bytes), so that large apps don't
+// completely deflate the balloon.
+const base::FeatureParam<int> kVmBalloonPolicyResponsiveMaxDeflateBytes{
+    &kVmBalloonPolicy, "responsive_max_deflate_bytes", 256 * 1024 * 1024};
+
 }  // namespace arc
diff --git a/ash/components/arc/arc_features.h b/ash/components/arc/arc_features.h
index 4fd37519..b29150b 100644
--- a/ash/components/arc/arc_features.h
+++ b/ash/components/arc/arc_features.h
@@ -30,6 +30,7 @@
 extern const base::Feature kGmsCoreLowMemoryKillerProtection;
 extern const base::Feature kGuestZram;
 extern const base::FeatureParam<int> kGuestZramSize;
+extern const base::Feature kLockGuestMemory;
 extern const base::Feature kLogdConfig;
 extern const base::FeatureParam<int> kLogdConfigSize;
 extern const base::Feature kKeyboardShortcutHelperIntegrationFeature;
@@ -56,6 +57,9 @@
 extern const base::FeatureParam<int> kVmBalloonPolicyReclaimKiB;
 extern const base::Feature kVmBroadcastPreNotifyANR;
 extern const base::Feature kVmGmsCoreLowMemoryKillerProtection;
+extern const base::FeatureParam<bool> kVmBalloonPolicyResponsive;
+extern const base::FeatureParam<int> kVmBalloonPolicyResponsiveTimeoutMs;
+extern const base::FeatureParam<int> kVmBalloonPolicyResponsiveMaxDeflateBytes;
 
 }  // namespace arc
 
diff --git a/ash/components/arc/disk_quota/arc_disk_quota_bridge.cc b/ash/components/arc/disk_quota/arc_disk_quota_bridge.cc
index f9c086dd..18157470 100644
--- a/ash/components/arc/disk_quota/arc_disk_quota_bridge.cc
+++ b/ash/components/arc/disk_quota/arc_disk_quota_bridge.cc
@@ -8,7 +8,6 @@
 
 #include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "ash/components/arc/session/arc_bridge_service.h"
-#include "ash/components/cryptohome/cryptohome_parameters.h"
 #include "base/bind.h"
 #include "base/memory/singleton.h"
 #include "chromeos/ash/components/dbus/spaced/spaced_client.h"
@@ -37,56 +36,9 @@
   ~ArcDiskQuotaBridgeFactory() override = default;
 };
 
-constexpr char kAndroidDownloadPath[] = "/storage/emulated/0/Download/";
-constexpr char kAndroidExternalStoragePath[] = "/storage/emulated/0/";
-constexpr char kAndroidDataMediaPath[] = "/data/media/0/";
-
 }  // namespace
 
 // static
-bool ArcDiskQuotaBridge::convertPathForSetProjectId(
-    const base::FilePath& android_path,
-    user_data_auth::SetProjectIdAllowedPathType* parent_path_out,
-    base::FilePath* child_path_out) {
-  const base::FilePath kDownloadPath(kAndroidDownloadPath);
-  const base::FilePath kExternalStoragePath(kAndroidExternalStoragePath);
-  const base::FilePath kDataMediaPath(kAndroidDataMediaPath);
-
-  if (android_path.ReferencesParent()) {
-    LOG(ERROR) << "Path contains \"..\" : " << android_path.value();
-    return false;
-  }
-
-  *child_path_out = base::FilePath();
-  if (kDownloadPath.IsParent(android_path)) {
-    // /storage/emulated/0/Download/* =>
-    //     parent=/home/user/<hash>/MyFiles/Downloads/, child=*
-    *parent_path_out =
-        user_data_auth::SetProjectIdAllowedPathType::PATH_DOWNLOADS;
-    return kDownloadPath.AppendRelativePath(android_path, child_path_out);
-  } else if (kExternalStoragePath.IsParent(android_path)) {
-    // /storage/emulated/0/* =>
-    //     parent=/home/root/<hash>/android-data/, child=data/media/0/*
-    *parent_path_out =
-        user_data_auth::SetProjectIdAllowedPathType::PATH_ANDROID_DATA;
-    // child_path should be relative to the root.
-    return base::FilePath("/").AppendRelativePath(kDataMediaPath,
-                                                  child_path_out) &&
-           kExternalStoragePath.AppendRelativePath(android_path,
-                                                   child_path_out);
-  } else if (kDataMediaPath.IsParent(android_path)) {
-    // /data/media/0/* =>
-    //     parent=/home/root/<hash>/android-data/, child=data/media/0/*
-    *parent_path_out =
-        user_data_auth::SetProjectIdAllowedPathType::PATH_ANDROID_DATA;
-    // child_path should be relative to the root.
-    return base::FilePath("/").AppendRelativePath(android_path, child_path_out);
-  } else {
-    return false;
-  }
-}
-
-// static
 ArcDiskQuotaBridge* ArcDiskQuotaBridge::GetForBrowserContext(
     content::BrowserContext* context) {
   return ArcDiskQuotaBridgeFactory::GetForBrowserContext(context);
@@ -195,45 +147,6 @@
           std::move(callback), project_id));
 }
 
-void ArcDiskQuotaBridge::SetProjectId(uint32_t project_id,
-                                      const std::string& android_path,
-                                      SetProjectIdCallback callback) {
-  user_data_auth::SetProjectIdAllowedPathType parent_path;
-  base::FilePath child_path;
-  if (!convertPathForSetProjectId(base::FilePath(android_path), &parent_path,
-                                  &child_path)) {
-    LOG(ERROR) << "Setting a project ID to path " << android_path
-               << " is not allowed";
-    std::move(callback).Run(false);
-    return;
-  }
-
-  user_data_auth::SetProjectIdRequest request;
-  request.set_project_id(project_id);
-  request.set_parent_path(parent_path);
-  request.set_child_path(child_path.value());
-  *request.mutable_account_id() =
-      cryptohome::CreateAccountIdentifierFromAccountId(account_id_);
-  ash::ArcQuotaClient::Get()->SetProjectId(
-      request,
-      base::BindOnce(
-          [](SetProjectIdCallback callback, const int project_id,
-             const user_data_auth::SetProjectIdAllowedPathType parent_path,
-             const std::string& child_path,
-             absl::optional<user_data_auth::SetProjectIdReply> reply) {
-            LOG_IF(ERROR, !reply.has_value())
-                << "Failed to set project ID " << project_id
-                << " to parent_path=" << parent_path
-                << " child_path=" << child_path;
-            bool result = false;
-            if (reply.has_value()) {
-              result = reply->success();
-            }
-            std::move(callback).Run(result);
-          },
-          std::move(callback), project_id, parent_path, child_path.value()));
-}
-
 void ArcDiskQuotaBridge::GetFreeDiskSpace(GetFreeDiskSpaceCallback callback) {
   ash::SpacedClient::Get()->GetFreeDiskSpace(
       "/home", base::BindOnce(&ArcDiskQuotaBridge::OnGetFreeDiskSpace,
diff --git a/ash/components/arc/disk_quota/arc_disk_quota_bridge.h b/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
index 4e658f7..2f96e690 100644
--- a/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
+++ b/ash/components/arc/disk_quota/arc_disk_quota_bridge.h
@@ -6,7 +6,6 @@
 #define ASH_COMPONENTS_ARC_DISK_QUOTA_ARC_DISK_QUOTA_BRIDGE_H_
 
 #include "ash/components/arc/mojom/disk_quota.mojom.h"
-#include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/cryptohome/UserDataAuth.pb.h"
 #include "components/account_id/account_id.h"
@@ -30,15 +29,6 @@
   static ArcDiskQuotaBridge* GetForBrowserContext(
       content::BrowserContext* context);
 
-  // Converts an Android path to a pair of (parent_path, child_path) to be
-  // passed to SetProjectId() on cryptohome.
-  // Returns false if SetProjectId() is not allowed for the path.
-  // (go/arc-project-quota)
-  static bool convertPathForSetProjectId(
-      const base::FilePath& android_path,
-      user_data_auth::SetProjectIdAllowedPathType* parent_path_out,
-      base::FilePath* child_path_out);
-
   ArcDiskQuotaBridge(content::BrowserContext* context,
                      ArcBridgeService* bridge_service);
 
@@ -62,10 +52,6 @@
       uint32_t project_id,
       GetCurrentSpaceForProjectIdCallback callback) override;
 
-  void SetProjectId(uint32_t project_id,
-                    const std::string& android_path,
-                    SetProjectIdCallback callback) override;
-
   void GetFreeDiskSpace(GetFreeDiskSpaceCallback) override;
 
  private:
diff --git a/ash/components/arc/disk_quota/arc_disk_quota_bridge_unittest.cc b/ash/components/arc/disk_quota/arc_disk_quota_bridge_unittest.cc
deleted file mode 100644
index bb4d152..0000000
--- a/ash/components/arc/disk_quota/arc_disk_quota_bridge_unittest.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/components/arc/disk_quota/arc_disk_quota_bridge.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace arc {
-namespace {
-
-using ArcDiskQuotaBridgeTest = testing::Test;
-using PathType = user_data_auth::SetProjectIdAllowedPathType;
-
-TEST(ArcDiskQuotaBridgeTest, ConvertPathForSetProjectId) {
-  PathType parent_path;
-  base::FilePath child_path;
-
-  EXPECT_TRUE(ArcDiskQuotaBridge::convertPathForSetProjectId(
-      base::FilePath("/storage/emulated/0/Download/mydir/test.png"),
-      &parent_path, &child_path));
-  EXPECT_EQ(PathType::PATH_DOWNLOADS, parent_path);
-  EXPECT_EQ("mydir/test.png", child_path.value());
-
-  EXPECT_TRUE(ArcDiskQuotaBridge::convertPathForSetProjectId(
-      base::FilePath("/storage/emulated/0/Pictures/test.png"), &parent_path,
-      &child_path));
-  EXPECT_EQ(PathType::PATH_ANDROID_DATA, parent_path);
-  EXPECT_EQ("data/media/0/Pictures/test.png", child_path.value());
-
-  EXPECT_TRUE(ArcDiskQuotaBridge::convertPathForSetProjectId(
-      base::FilePath("/data/media/0/Movies/test.mp4"), &parent_path,
-      &child_path));
-  EXPECT_EQ(PathType::PATH_ANDROID_DATA, parent_path);
-  EXPECT_EQ("data/media/0/Movies/test.mp4", child_path.value());
-
-  // Unallowed path.
-  EXPECT_FALSE(ArcDiskQuotaBridge::convertPathForSetProjectId(
-      base::FilePath("/storage/other/path"), &parent_path, &child_path));
-
-  // Path contains ".."
-  EXPECT_FALSE(ArcDiskQuotaBridge::convertPathForSetProjectId(
-      base::FilePath("/data/media/0/../test.png"), &parent_path, &child_path));
-}
-
-}  // namespace
-}  // namespace arc
diff --git a/ash/components/arc/memory_pressure/arc_memory_pressure_bridge_unittest.cc b/ash/components/arc/memory_pressure/arc_memory_pressure_bridge_unittest.cc
index 9d871041..f57d8b6 100644
--- a/ash/components/arc/memory_pressure/arc_memory_pressure_bridge_unittest.cc
+++ b/ash/components/arc/memory_pressure/arc_memory_pressure_bridge_unittest.cc
@@ -116,15 +116,19 @@
 // priority.
 TEST_F(ArcMemoryPressureBridgeTest, PressureCached) {
   ASSERT_NE(nullptr, bridge());
+  // Check for overflow for large reclaim values by passing 5 GiB to the
+  // callback, and then check that we report 5 MiB * KiB estimated_freed_kib.
+  process_instance().set_apply_host_memory_pressure_response(
+      1 /* killed */, UINT64_C(5368709120) /* reclaimed */);
   resourced().FakeArcVmMemoryPressure(
       chromeos::ResourcedClient::PressureLevelArcVm::CACHED,
       1 /* reclaim_target_kb */);
   ASSERT_TRUE(process_instance().CheckLastHostMemoryPressure(
       mojom::PressureLevel::kCached, 1024 /* reclaim_target */));
-  // Check for overflow for large reclaim values by passing 5 GiB to the
-  // callback, and then check that we report 5 MiB * KiB estimated_freed_kib.
-  process_instance().RunHostMemoryPressureCallback(
-      1 /* killed */, UINT64_C(5368709120) /* reclaimed */);
+
+  // Run the ApplyHostMemoryPressure callback.
+  base::RunLoop().RunUntilIdle();
+
   ASSERT_TRUE(kill_observer().CheckLastMemoryPressureKill(
       1 /* count */, 5242880 /* estimated_freed_kb */));
 }
@@ -132,13 +136,17 @@
 // Tests that PERCEPTIBLE memory pressure triggers kills of R_TOP priority.
 TEST_F(ArcMemoryPressureBridgeTest, PressurePerceptible) {
   ASSERT_NE(nullptr, bridge());
+  process_instance().set_apply_host_memory_pressure_response(
+      1 /* killed */, 2048 /* reclaimed */);
   resourced().FakeArcVmMemoryPressure(
       chromeos::ResourcedClient::PressureLevelArcVm::PERCEPTIBLE,
       1 /* reclaim_target_kb */);
   ASSERT_TRUE(process_instance().CheckLastHostMemoryPressure(
       mojom::PressureLevel::kPerceptible, 1024 /* reclaim_target */));
-  process_instance().RunHostMemoryPressureCallback(1 /* killed */,
-                                                   2048 /* reclaimed */);
+
+  // Run the ApplyHostMemoryPressure callback.
+  base::RunLoop().RunUntilIdle();
+
   ASSERT_TRUE(kill_observer().CheckLastMemoryPressureKill(
       1 /* count */, 2 /* estimated_freed_kb */));
 }
@@ -146,13 +154,17 @@
 // Tests that FOREGROUND memory pressure triggers kills of R_TOP priority.
 TEST_F(ArcMemoryPressureBridgeTest, PressureForeground) {
   ASSERT_NE(nullptr, bridge());
+  process_instance().set_apply_host_memory_pressure_response(
+      1 /* killed */, 2048 /* reclaimed */);
   resourced().FakeArcVmMemoryPressure(
       chromeos::ResourcedClient::PressureLevelArcVm::FOREGROUND,
       1 /* reclaim_target_kb */);
   ASSERT_TRUE(process_instance().CheckLastHostMemoryPressure(
       mojom::PressureLevel::kForeground, 1024 /* reclaim_target */));
-  process_instance().RunHostMemoryPressureCallback(1 /* killed */,
-                                                   2048 /* reclaimed */);
+
+  // Run the ApplyHostMemoryPressure callback.
+  base::RunLoop().RunUntilIdle();
+
   ASSERT_TRUE(kill_observer().CheckLastMemoryPressureKill(
       1 /* count */, 2 /* estimated_freed_kb */));
 }
@@ -161,6 +173,8 @@
 // only cause one call into ARCVM.
 TEST_F(ArcMemoryPressureBridgeTest, DebouncePressure) {
   ASSERT_NE(nullptr, bridge());
+  process_instance().set_apply_host_memory_pressure_response(
+      1 /* killed */, 2048 /* reclaimed */);
 
   // FakeProcessInstance::HostMemoryPressure will DCHECK if
   // FakeProcessInstance::CheckLastHostMemoryPressure is not called first. So
@@ -176,19 +190,25 @@
   // did not get forwarded to Mojo.
   ASSERT_TRUE(process_instance().CheckLastHostMemoryPressure(
       mojom::PressureLevel::kPerceptible, 1024 /* reclaim_target */));
-  process_instance().RunHostMemoryPressureCallback(1 /* killed */,
-                                                   2048 /* reclaimed */);
+
+  // Run the ApplyHostMemoryPressure callback.
+  base::RunLoop().RunUntilIdle();
+
   ASSERT_TRUE(kill_observer().CheckLastMemoryPressureKill(
       1 /* count */, 2 /* estimated_freed_kb */));
 
   // Check that we do forward the next call after the callback is executed.
+  process_instance().set_apply_host_memory_pressure_response(
+      3 /* killed */, 4096 /* reclaimed */);
   resourced().FakeArcVmMemoryPressure(
       chromeos::ResourcedClient::PressureLevelArcVm::PERCEPTIBLE,
       3 /* reclaim_target_kb */);
   ASSERT_TRUE(process_instance().CheckLastHostMemoryPressure(
       mojom::PressureLevel::kPerceptible, 3072 /* reclaim_target */));
-  process_instance().RunHostMemoryPressureCallback(3 /* killed */,
-                                                   4096 /* reclaimed */);
+
+  // Run the ApplyHostMemoryPressure callback.
+  base::RunLoop().RunUntilIdle();
+
   ASSERT_TRUE(kill_observer().CheckLastMemoryPressureKill(
       3 /* count */, 4 /* estimated_freed_kb */));
 }
diff --git a/ash/components/arc/metrics/arc_metrics_service_unittest.cc b/ash/components/arc/metrics/arc_metrics_service_unittest.cc
index 182ca89..695ec4db 100644
--- a/ash/components/arc/metrics/arc_metrics_service_unittest.cc
+++ b/ash/components/arc/metrics/arc_metrics_service_unittest.cc
@@ -77,6 +77,12 @@
       command_line->InitFromArgv({"", "--enable-arcvm"});
     }
     arc_service_manager_ = std::make_unique<ArcServiceManager>();
+    // ArcMetricsService makes one call to RequestLowMemoryKillCounts when it
+    // starts, so make it return 0s.
+    fake_process_instance_.set_request_low_memory_kill_counts_response(
+        mojom::LowMemoryKillCounts::New(0, 0, 0, 0, 0, 0, 0));
+    ArcServiceManager::Get()->arc_bridge_service()->process()->SetInstance(
+        &fake_process_instance_);
     context_ = std::make_unique<TestBrowserContext>();
     prefs::RegisterLocalStatePrefs(context_->pref_registry());
     prefs::RegisterProfilePrefs(context_->pref_registry());
@@ -85,9 +91,6 @@
     service_->set_prefs(context_->prefs());
 
     CreateFakeWindows();
-
-    ArcServiceManager::Get()->arc_bridge_service()->process()->SetInstance(
-        &fake_process_instance_);
   }
 
   ~ArcMetricsServiceTest() override {
@@ -131,10 +134,6 @@
 
   FakeProcessInstance& process_instance() { return fake_process_instance_; }
 
- protected:
-  content::BrowserTaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-
  private:
   void CreateFakeWindows() {
     fake_arc_window_.reset(aura::test::CreateTestWindowWithId(
@@ -145,6 +144,9 @@
         /*id=*/1, nullptr));
   }
 
+  content::BrowserTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
   TestingPrefServiceSimple local_state_;
   session_manager::SessionManager session_manager_;
 
@@ -419,16 +421,13 @@
  protected:
   ArcVmArcMetricsServiceTest() : ArcMetricsServiceTest(true) {}
 
-  void RespondToFirstKillCountsRequest(mojom::LowMemoryKillCountsPtr counts) {
-    process_instance().RunRequestLowMemoryKillCountsCallback(std::move(counts));
-  }
-
   void RequestKillCountsAndRespond(mojom::LowMemoryKillCountsPtr counts) {
     ash::FakeConciergeClient::Get()->set_list_vms_response(
         std::move(GetParam()));
+    process_instance().set_request_low_memory_kill_counts_response(
+        std::move(counts));
     service()->RequestKillCountsForTesting();
-    task_environment_.RunUntilIdle();
-    process_instance().RunRequestLowMemoryKillCountsCallback(std::move(counts));
+    base::RunLoop().RunUntilIdle();
   }
 };
 
@@ -585,47 +584,9 @@
 
 TEST_P(ArcVmArcMetricsServiceTest, AppLowMemoryKills) {
   base::HistogramTester tester;
+  // The test code sets the initial counts to 0.
+  auto c0 = mojom::LowMemoryKillCounts::New(0, 0, 0, 0, 0, 0, 0);
   // First sample counts.
-  auto c0 = mojom::LowMemoryKillCounts::New(1,   // oom.
-                                            2,   // lmkd_foreground.
-                                            3,   // lmkd_perceptible.
-                                            4,   // lmkd_cached.
-                                            5,   // pressure_foreground.
-                                            6,   // pressure_perceptible.
-                                            7);  // pressure_cached.
-  // Second sample counts.
-  auto c1 = mojom::LowMemoryKillCounts::New(17,   // oom.
-                                            16,   // lmkd_foreground.
-                                            15,   // lmkd_perceptible.
-                                            14,   // lmkd_cached.
-                                            13,   // pressure_foreground.
-                                            12,   // pressure_perceptible.
-                                            11);  // pressure_cached.
-  // ArcMetricsService requests kill counts on startup, so respond to that
-  // before making a new request.
-  RespondToFirstKillCountsRequest(c0->Clone());
-
-  // The first callback doesn't log to histograms, since it's collecting the
-  // first baseline.
-  ExpectNoAppKillCounts(tester);
-
-  // Send another counter response, which should log the increase to histograms.
-  RequestKillCountsAndRespond(c1->Clone());
-  ExpectOneSampleAppKillCounts(tester, GetParam(), c0, c1);
-}
-
-TEST_P(ArcVmArcMetricsServiceTest, AppLowMemoryKillsDecrease) {
-  base::HistogramTester tester;
-  // First sample counts.
-  auto c0 = mojom::LowMemoryKillCounts::New(17,   // oom.
-                                            16,   // lmkd_foreground.
-                                            15,   // lmkd_perceptible.
-                                            14,   // lmkd_cached.
-                                            13,   // pressure_foreground.
-                                            12,   // pressure_perceptible.
-                                            11);  // pressure_cached.
-
-  // Second sample counts.
   auto c1 = mojom::LowMemoryKillCounts::New(1,   // oom.
                                             2,   // lmkd_foreground.
                                             3,   // lmkd_perceptible.
@@ -633,21 +594,41 @@
                                             5,   // pressure_foreground.
                                             6,   // pressure_perceptible.
                                             7);  // pressure_cached.
+  // Second sample counts.
+  auto c2 = mojom::LowMemoryKillCounts::New(17,   // oom.
+                                            16,   // lmkd_foreground.
+                                            15,   // lmkd_perceptible.
+                                            14,   // lmkd_cached.
+                                            13,   // pressure_foreground.
+                                            12,   // pressure_perceptible.
+                                            11);  // pressure_cached.
+  // Third sample counts all decrease by 1.
+  auto c3 = mojom::LowMemoryKillCounts::New(16,   // oom.
+                                            15,   // lmkd_foreground.
+                                            14,   // lmkd_perceptible.
+                                            13,   // lmkd_cached.
+                                            12,   // pressure_foreground.
+                                            11,   // pressure_perceptible.
+                                            10);  // pressure_cached.
 
-  // ArcMetricsService requests kill counts on startup, so respond to that
-  // before making a new request.
-  RespondToFirstKillCountsRequest(c0->Clone());
+  {
+    base::HistogramTester tester;
+    RequestKillCountsAndRespond(c1->Clone());
+    ExpectOneSampleAppKillCounts(tester, GetParam(), c0, c1);
+  }
 
-  // The first callback doesn't log to histograms, since it's collecting the
-  // first baseline.
-  ExpectNoAppKillCounts(tester);
+  {
+    base::HistogramTester tester;
+    RequestKillCountsAndRespond(c2->Clone());
+    ExpectOneSampleAppKillCounts(tester, GetParam(), c1, c2);
+  }
 
-  // Send another counter response, which should log the increase to histograms.
-  RequestKillCountsAndRespond(c1->Clone());
-
-  // Except that all the counters decreased, so we don't expect anything to be
-  // logged.
-  ExpectNoAppKillCounts(tester);
+  {
+    base::HistogramTester tester;
+    RequestKillCountsAndRespond(c3->Clone());
+    // Counts decreased, so expect no samples.
+    ExpectNoAppKillCounts(tester);
+  }
 }
 
 }  // namespace
diff --git a/ash/components/arc/mojom/disk_quota.mojom b/ash/components/arc/mojom/disk_quota.mojom
index 4d0c67c0..be026af 100644
--- a/ash/components/arc/mojom/disk_quota.mojom
+++ b/ash/components/arc/mojom/disk_quota.mojom
@@ -11,6 +11,7 @@
 };
 
 // Next Method ID: 6
+// Deprecated method ID: 4
 interface DiskQuotaHost {
   // Whether cryptohome supports quota-based stats.
   IsQuotaSupported@0() => (bool supported);
@@ -25,12 +26,6 @@
   [MinVersion=1] GetCurrentSpaceForProjectId@3(uint32 project_id) =>
       (int64 cur_space);
 
-  // Set a project ID on a file path.
-  // Host is supposed to convert the given Android file path to the
-  // corresponding path in Chrome OS file system.
-  [MinVersion=1] SetProjectId@4(uint32 project_id, string android_file_path) =>
-      (bool success);
-
   // Get free disk space in the stateful partition.
   [MinVersion=2] GetFreeDiskSpace@5() => (DiskSpace? free_space);
 };
diff --git a/ash/components/arc/session/arc_vm_client_adapter.cc b/ash/components/arc/session/arc_vm_client_adapter.cc
index d00d18db..827594f 100644
--- a/ash/components/arc/session/arc_vm_client_adapter.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter.cc
@@ -449,6 +449,9 @@
   // Add hugepages.
   request.set_use_hugepages(IsArcVmUseHugePages());
 
+  // Request guest memory locking, if configured.
+  request.set_lock_guest_memory(base::FeatureList::IsEnabled(kLockGuestMemory));
+
   // Specify VM Memory.
   if (base::FeatureList::IsEnabled(kVmMemorySize)) {
     base::SystemMemoryInfoKB info;
@@ -496,6 +499,11 @@
     balloon_policy->set_moderate_target_cache(moderate_kib * 1024);
     balloon_policy->set_critical_target_cache(critical_kib * 1024);
     balloon_policy->set_reclaim_target_cache(reclaim_kib * 1024);
+    balloon_policy->set_responsive(kVmBalloonPolicyResponsive.Get());
+    balloon_policy->set_responsive_timeout_ms(
+        kVmBalloonPolicyResponsiveTimeoutMs.Get());
+    balloon_policy->set_responsive_max_deflate_bytes(
+        kVmBalloonPolicyResponsiveMaxDeflateBytes.Get());
     VLOG(1) << "Use LimitCacheBalloonPolicy. ModerateKiB=" << moderate_kib
             << ", CriticalKiB=" << critical_kib
             << ", ReclaimKiB=" << reclaim_kib;
diff --git a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
index 911cd38..26d8586 100644
--- a/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
+++ b/ash/components/arc/session/arc_vm_client_adapter_unittest.cc
@@ -2034,11 +2034,22 @@
   EXPECT_TRUE(request.use_hugepages());
 }
 
-TEST_F(ArcVmClientAdapterTest, ArcVmUseHugePagesDisabled) {
+TEST_F(ArcVmClientAdapterTest, ArcVmLockGuestMemoryEnabled) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(kLockGuestMemory);
   StartParams start_params(GetPopulatedStartParams());
   StartMiniArcWithParams(true, std::move(start_params));
   auto request = GetTestConciergeClient()->start_arc_vm_request();
+  EXPECT_TRUE(request.lock_guest_memory());
+}
+
+TEST_F(ArcVmClientAdapterTest, ArcVmMemoryOptionsDisabled) {
+  StartParams start_params(GetPopulatedStartParams());
+  StartMiniArcWithParams(true, std::move(start_params));
+  auto request = GetTestConciergeClient()->start_arc_vm_request();
+  // Verify that both options are disabled by default.
   EXPECT_FALSE(request.use_hugepages());
+  EXPECT_FALSE(request.lock_guest_memory());
 }
 
 // Test that StartArcVmRequest has no memory_mib field when kVmMemorySize is
diff --git a/ash/components/arc/test/fake_process_instance.cc b/ash/components/arc/test/fake_process_instance.cc
index b3deda8..09a1af2 100644
--- a/ash/components/arc/test/fake_process_instance.cc
+++ b/ash/components/arc/test/fake_process_instance.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/check_op.h"
+#include "base/threading/thread_task_runner_handle.h"
 
 namespace arc {
 
@@ -50,13 +51,21 @@
   host_memory_pressure_checked_ = false;
   host_memory_pressure_level_ = level;
   host_memory_pressure_reclaim_target_ = reclaim_target;
-  host_memory_pressure_callback_ = std::move(callback);
+
+  DCHECK(host_memory_pressure_response_);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), host_memory_pressure_response_->first,
+                     host_memory_pressure_response_->second));
+  host_memory_pressure_response_ = absl::nullopt;
 }
 
 void FakeProcessInstance::RequestLowMemoryKillCounts(
     RequestLowMemoryKillCountsCallback callback) {
-  DCHECK(!request_low_memory_kill_counts_callback_);
-  request_low_memory_kill_counts_callback_ = std::move(callback);
+  DCHECK(low_memory_kill_counts_response_);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback),
+                                std::move(*low_memory_kill_counts_response_)));
 }
 
 bool FakeProcessInstance::CheckLastHostMemoryPressure(
@@ -68,17 +77,4 @@
          reclaim_target == host_memory_pressure_reclaim_target_;
 }
 
-void FakeProcessInstance::RunHostMemoryPressureCallback(uint32_t killed,
-                                                        uint64_t reclaimed) {
-  DCHECK(host_memory_pressure_callback_);
-  // NB: two moves, one to reset the unique_ptr, and one to reset the callback.
-  std::move(host_memory_pressure_callback_).Run(killed, reclaimed);
-}
-
-void FakeProcessInstance::RunRequestLowMemoryKillCountsCallback(
-    mojom::LowMemoryKillCountsPtr counts) {
-  DCHECK(request_low_memory_kill_counts_callback_);
-  std::move(request_low_memory_kill_counts_callback_).Run(std::move(counts));
-}
-
 }  // namespace arc
diff --git a/ash/components/arc/test/fake_process_instance.h b/ash/components/arc/test/fake_process_instance.h
index 708bb00..cc45a6f 100644
--- a/ash/components/arc/test/fake_process_instance.h
+++ b/ash/components/arc/test/fake_process_instance.h
@@ -5,9 +5,13 @@
 #ifndef ASH_COMPONENTS_ARC_TEST_FAKE_PROCESS_INSTANCE_H_
 #define ASH_COMPONENTS_ARC_TEST_FAKE_PROCESS_INSTANCE_H_
 
+#include <deque>
+#include <utility>
+
 #include "ash/components/arc/mojom/process.mojom.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace arc {
 
@@ -48,22 +52,28 @@
     return host_memory_pressure_checked_;
   }
 
-  // Executes the callback from the last call to HostMemoryPressure.
-  void RunHostMemoryPressureCallback(uint32_t killed, uint64_t reclaimed);
+  void set_apply_host_memory_pressure_response(uint32_t killed,
+                                               uint64_t reclaimed) {
+    host_memory_pressure_response_ = std::pair(killed, reclaimed);
+  }
 
-  // Executes the callback from the last call to RequestLowMemoryKillCounts.
-  void RunRequestLowMemoryKillCountsCallback(
-      mojom::LowMemoryKillCountsPtr counts);
+  void set_request_low_memory_kill_counts_response(
+      arc::mojom::LowMemoryKillCountsPtr response) {
+    low_memory_kill_counts_response_ = std::move(response);
+  }
 
  private:
   // State to save the most recent call to HostMemoryPressure.
   bool host_memory_pressure_checked_ = true;
   mojom::PressureLevel host_memory_pressure_level_;
   int64_t host_memory_pressure_reclaim_target_;
-  ApplyHostMemoryPressureCallback host_memory_pressure_callback_;
 
-  // State to save the most recent call to RequestLowMemoryKillCounts.
-  RequestLowMemoryKillCountsCallback request_low_memory_kill_counts_callback_;
+  // Response to next call to  ApplyHostMemoryPressure.
+  absl::optional<std::pair<uint32_t, uint64_t>> host_memory_pressure_response_;
+
+  // Response to next call to RequestLowMemoryKillCounts.
+  absl::optional<arc::mojom::LowMemoryKillCountsPtr>
+      low_memory_kill_counts_response_;
 };
 
 }  // namespace arc
diff --git a/ash/components/drivefs/drivefs_host.cc b/ash/components/drivefs/drivefs_host.cc
index 605301e..04328c9 100644
--- a/ash/components/drivefs/drivefs_host.cc
+++ b/ash/components/drivefs/drivefs_host.cc
@@ -122,6 +122,12 @@
     }
   }
 
+  void OnMirrorSyncingStatusUpdate(mojom::SyncingStatusPtr status) override {
+    for (auto& observer : host_->observers_) {
+      observer.OnMirrorSyncingStatusUpdate(*status);
+    }
+  }
+
   void OnFilesChanged(std::vector<mojom::FileChangePtr> changes) override {
     std::vector<mojom::FileChange> changes_values;
     changes_values.reserve(changes.size());
diff --git a/ash/components/drivefs/drivefs_host_observer.h b/ash/components/drivefs/drivefs_host_observer.h
index d676b96..cf63e46 100644
--- a/ash/components/drivefs/drivefs_host_observer.h
+++ b/ash/components/drivefs/drivefs_host_observer.h
@@ -18,6 +18,8 @@
  public:
   virtual void OnUnmounted() {}
   virtual void OnSyncingStatusUpdate(const mojom::SyncingStatus& status) {}
+  virtual void OnMirrorSyncingStatusUpdate(const mojom::SyncingStatus& status) {
+  }
   virtual void OnFilesChanged(const std::vector<mojom::FileChange>& changes) {}
   virtual void OnError(const mojom::DriveError& error) {}
 
diff --git a/ash/components/drivefs/drivefs_host_unittest.cc b/ash/components/drivefs/drivefs_host_unittest.cc
index d28fafa..92625794 100644
--- a/ash/components/drivefs/drivefs_host_unittest.cc
+++ b/ash/components/drivefs/drivefs_host_unittest.cc
@@ -50,6 +50,7 @@
 using base::test::RunOnceClosure;
 using testing::_;
 using MountFailure = DriveFsHost::MountObserver::MountFailure;
+using ChangeLogOptionPair = std::pair<int64_t, std::string>;
 
 constexpr base::TimeDelta kTokenLifetime = base::Hours(1);
 
@@ -63,8 +64,9 @@
     return nullptr;
   }
 
-  void FetchChangeLog(std::vector<mojom::FetchChangeLogOptionsPtr> options) {
-    std::vector<std::pair<int64_t, std::string>> unwrapped_options;
+  void FetchChangeLog(
+      std::vector<mojom::FetchChangeLogOptionsPtr> options) override {
+    std::vector<ChangeLogOptionPair> unwrapped_options;
     for (auto& entry : options) {
       unwrapped_options.push_back(
           std::make_pair(entry->change_id, entry->team_drive_id));
@@ -72,12 +74,16 @@
     FetchChangeLogImpl(unwrapped_options);
   }
 
-  MOCK_METHOD1(
-      FetchChangeLogImpl,
-      void(const std::vector<std::pair<int64_t, std::string>>& options));
-  MOCK_METHOD0(FetchAllChangeLogs, void());
+  MOCK_METHOD(void,
+              FetchChangeLogImpl,
+              (const std::vector<ChangeLogOptionPair>&));
 
-  MOCK_CONST_METHOD1(OnStartSearchQuery, void(const mojom::QueryParameters&));
+  MOCK_METHOD(void, FetchAllChangeLogs, ());
+
+  MOCK_METHOD(void,
+              OnStartSearchQuery,
+              (const mojom::QueryParameters&),
+              (const));
   void StartSearchQuery(mojo::PendingReceiver<mojom::SearchQuery> receiver,
                         mojom::QueryParametersPtr query_params) override {
     search_receiver_.reset();
@@ -85,9 +91,9 @@
     search_receiver_.Bind(std::move(receiver));
   }
 
-  MOCK_METHOD1(OnGetNextPage,
-               drive::FileError(
-                   absl::optional<std::vector<mojom::QueryItemPtr>>* items));
+  MOCK_METHOD(drive::FileError,
+              OnGetNextPage,
+              (absl::optional<std::vector<mojom::QueryItemPtr>> * items));
 
   void GetNextPage(GetNextPageCallback callback) override {
     absl::optional<std::vector<mojom::QueryItemPtr>> items;
@@ -130,10 +136,11 @@
   }
 
   // DriveFsHost::MountObserver:
-  MOCK_METHOD1(OnMounted, void(const base::FilePath&));
-  MOCK_METHOD2(OnMountFailed,
-               void(MountFailure, absl::optional<base::TimeDelta>));
-  MOCK_METHOD1(OnUnmounted, void(absl::optional<base::TimeDelta>));
+  MOCK_METHOD(void, OnMounted, (const base::FilePath&));
+  MOCK_METHOD(void,
+              OnMountFailed,
+              (MountFailure, absl::optional<base::TimeDelta>));
+  MOCK_METHOD(void, OnUnmounted, (absl::optional<base::TimeDelta>));
 
   drive::DriveNotificationManager& GetDriveNotificationManager() override {
     return drive_notification_manager_;
@@ -194,11 +201,17 @@
 
 class MockDriveFsHostObserver : public DriveFsHostObserver {
  public:
-  MOCK_METHOD0(OnUnmounted, void());
-  MOCK_METHOD1(OnSyncingStatusUpdate, void(const mojom::SyncingStatus& status));
-  MOCK_METHOD1(OnFilesChanged,
-               void(const std::vector<mojom::FileChange>& changes));
-  MOCK_METHOD1(OnError, void(const mojom::DriveError& error));
+  MOCK_METHOD(void, OnUnmounted, ());
+  MOCK_METHOD(void,
+              OnSyncingStatusUpdate,
+              (const mojom::SyncingStatus& status));
+  MOCK_METHOD(void,
+              OnMirrorSyncingStatusUpdate,
+              (const mojom::SyncingStatus& status));
+  MOCK_METHOD(void,
+              OnFilesChanged,
+              (const std::vector<mojom::FileChange>& changes));
+  MOCK_METHOD(void, OnError, (const mojom::DriveError& error));
 };
 
 class DriveFsHostTest : public ::testing::Test, public mojom::DriveFsBootstrap {
@@ -679,8 +692,8 @@
   delegate_.FlushForTesting();
 
   EXPECT_CALL(mock_drivefs_,
-              FetchChangeLogImpl(std::vector<std::pair<int64_t, std::string>>{
-                  {123, ""}, {456, "a"}}));
+              FetchChangeLogImpl(
+                  std::vector<ChangeLogOptionPair>{{123, ""}, {456, "a"}}));
 
   for (auto& observer :
        host_delegate_->GetDriveNotificationManager().observers_for_test()) {
@@ -852,5 +865,25 @@
   EXPECT_EQ("foo", host_delegate_->get_last_extension_params().extension_id);
 }
 
+TEST_F(DriveFsHostTest, OnMirrorSyncingStatusUpdate_ForwardToObservers) {
+  ASSERT_NO_FATAL_FAILURE(DoMount());
+  MockDriveFsHostObserver observer;
+  base::ScopedObservation<DriveFsHost, DriveFsHostObserver> observation_scoper(
+      &observer);
+  observation_scoper.Observe(host_.get());
+  auto status = mojom::SyncingStatus::New();
+  status->item_events.emplace_back(absl::in_place, 12, 34, "filename.txt",
+                                   mojom::ItemEvent::State::kInProgress, 123,
+                                   456, mojom::ItemEventReason::kPin);
+  mojom::SyncingStatusPtr observed_status;
+  EXPECT_CALL(observer, OnMirrorSyncingStatusUpdate(_))
+      .WillOnce(CloneStruct(&observed_status));
+  delegate_->OnMirrorSyncingStatusUpdate(status.Clone());
+  delegate_.FlushForTesting();
+  testing::Mock::VerifyAndClear(&observer);
+
+  EXPECT_EQ(status, observed_status);
+}
+
 }  // namespace
 }  // namespace drivefs
diff --git a/ash/components/drivefs/drivefs_session_unittest.cc b/ash/components/drivefs/drivefs_session_unittest.cc
index af96201..cf0baa4 100644
--- a/ash/components/drivefs/drivefs_session_unittest.cc
+++ b/ash/components/drivefs/drivefs_session_unittest.cc
@@ -251,6 +251,7 @@
   void GetMachineRootID(
       mojom::DriveFsDelegate::GetMachineRootIDCallback callback) override {}
   void PersistMachineRootID(const std::string& id) override {}
+  void OnMirrorSyncingStatusUpdate(mojom::SyncingStatusPtr status) override {}
 };
 
 class DriveFsSessionTest : public ::testing::Test,
diff --git a/ash/components/drivefs/mojom/drivefs.mojom b/ash/components/drivefs/mojom/drivefs.mojom
index 6aca7cd..4e51b57 100644
--- a/ash/components/drivefs/mojom/drivefs.mojom
+++ b/ash/components/drivefs/mojom/drivefs.mojom
@@ -192,6 +192,10 @@
 
   // Invoked when the machine ID is calculated to store in Chrome device prefs.
   PersistMachineRootID(string doc_id);
+
+  // Invoked when the syncing status changes for items that are being tracked by
+  // the mirror stack.
+  OnMirrorSyncingStatusUpdate(SyncingStatus status);
 };
 
 // Next MinVersion: 7
diff --git a/ash/components/geolocation/simple_geolocation_provider.h b/ash/components/geolocation/simple_geolocation_provider.h
index 898c542..f8dc5d4 100644
--- a/ash/components/geolocation/simple_geolocation_provider.h
+++ b/ash/components/geolocation/simple_geolocation_provider.h
@@ -29,7 +29,7 @@
 // SimpleGeolocationProvider must be created and used on the same thread.
 //
 // Note: this should probably be a singleton to monitor requests rate.
-// But as it is used only diring ChromeOS Out-of-Box, it can be owned by
+// But as it is used only during ChromeOS Out-of-Box, it can be owned by
 // WizardController for now.
 class COMPONENT_EXPORT(ASH_GEOLOCATION) SimpleGeolocationProvider {
  public:
diff --git a/ash/components/geolocation/simple_geolocation_request.h b/ash/components/geolocation/simple_geolocation_request.h
index f4a3a73..5305b02 100644
--- a/ash/components/geolocation/simple_geolocation_request.h
+++ b/ash/components/geolocation/simple_geolocation_request.h
@@ -40,7 +40,7 @@
 // Note: we need COMPONENT_EXPORT(ASH_GEOLOCATION) for tests.
 class COMPONENT_EXPORT(ASH_GEOLOCATION) SimpleGeolocationRequest {
  public:
-  // Called when a new geo geolocation information is available.
+  // Called when a new geolocation information is available.
   // The second argument indicates whether there was a server error or not.
   // It is true when there was a server or network error - either no response
   // or a 500 error code.
diff --git a/ash/debug.cc b/ash/debug.cc
index b5a8385..95d1c49 100644
--- a/ash/debug.cc
+++ b/ash/debug.cc
@@ -46,6 +46,9 @@
   views::Widget* widget = views::Widget::GetWidgetForNativeView(active_window);
   if (!widget)
     return;
+
+  *out << "Host widget:\n";
+  views::PrintWidgetInformation(*widget, /*detailed*/ true, out);
   views::PrintViewHierarchy(widget->GetRootView(), out);
 }
 
@@ -64,7 +67,8 @@
   const gfx::Vector2dF& subpixel_position_offset =
       window->layer()->GetSubpixelOffset();
   *out << indent_str;
-  *out << name << " (" << window << ")"
+  *out << " [window]";
+  *out << " " << name << " (" << window << ")"
        << " type=" << window->GetType();
   int window_id = window->GetId();
   if (window_id != aura::Window::kInitialId)
@@ -103,6 +107,13 @@
     *out << " pkg_name=" << *pkg_name;
   *out << '\n';
 
+  views::Widget* widget = views::Widget::GetWidgetForNativeView(window);
+  if (widget) {
+    *out << std::string(indent + 3, ' ');
+    *out << " [widget]";
+    views::PrintWidgetInformation(*widget, /*detailed*/ false, out);
+  }
+
   for (aura::Window* child : window->children()) {
     PrintWindowHierarchy(active_window, focused_window, capture_window, child,
                          indent + 3, scrub_data, out_window_titles, out);
diff --git a/ash/webui/camera_app_ui/BUILD.gn b/ash/webui/camera_app_ui/BUILD.gn
index 905352e7..499c5ca 100644
--- a/ash/webui/camera_app_ui/BUILD.gn
+++ b/ash/webui/camera_app_ui/BUILD.gn
@@ -142,7 +142,7 @@
     generated_grdp_file,
   ]
 
-  manifest_files = [ "$target_gen_dir/resources/js/tsconfig.manifest" ]
+  manifest_files = [ "$target_gen_dir/resources/js/build_ts.manifest" ]
   input_files_base_dir = rebase_path("resources", "//")
   input_files = []
 
diff --git a/ash/webui/camera_app_ui/resources/css/main.css b/ash/webui/camera_app_ui/resources/css/main.css
index 5baed208..468a22e 100644
--- a/ash/webui/camera_app_ui/resources/css/main.css
+++ b/ash/webui/camera_app_ui/resources/css/main.css
@@ -830,6 +830,7 @@
 }
 
 #preview-video {
+  pointer-events: none;
   transition: opacity var(--fast2-duration) ease-in-out;
 }
 
diff --git a/ash/webui/camera_app_ui/resources/js/thumbnailer.ts b/ash/webui/camera_app_ui/resources/js/thumbnailer.ts
index 2d670eb9..e41cb3d0 100644
--- a/ash/webui/camera_app_ui/resources/js/thumbnailer.ts
+++ b/ash/webui/camera_app_ui/resources/js/thumbnailer.ts
@@ -53,8 +53,19 @@
       hasLoaded.signal(true);
     });
     const gotFrame = new WaitableEvent();
-    el.requestVideoFrameCallback(() => gotFrame.signal());
+    el.requestVideoFrameCallback(() => {
+      gotFrame.signal();
+    });
+    // Since callbacks registered in `requestVideoFrameCallback` doesn't fire
+    // when the page is in the background, use `timeupdate` event to indicate
+    // that the video has been played successfully. Note that waiting until
+    // `canplay` is not enough (see b/172214187).
+    el.addEventListener('timeupdate', () => {
+      gotFrame.signal();
+    }, {once: true});
+
     el.preload = 'auto';
+    el.muted = true;
     el.src = URL.createObjectURL(blob);
     if (!(await hasLoaded.wait())) {
       throw new LoadError(el.error?.message);
@@ -67,9 +78,8 @@
     }
 
     try {
-      // The |requestVideoFrameCallback| may not be triggered when playing
-      // malformed video. Set 1 second timeout here to prevent UI be blocked
-      // forever.
+      // `gotFrame` may not resolve when playing malformed video. Set 1 second
+      // timeout here to prevent UI from being blocked forever.
       await gotFrame.timedWait(1000);
     } catch (e) {
       throw new PlayMalformedError(assertInstanceof(e, Error).message);
diff --git a/ash/webui/color_internals/resources/BUILD.gn b/ash/webui/color_internals/resources/BUILD.gn
index acce4fa..e7d5944 100644
--- a/ash/webui/color_internals/resources/BUILD.gn
+++ b/ash/webui/color_internals/resources/BUILD.gn
@@ -8,20 +8,6 @@
 
 assert(is_chromeos_ash, "Color Internals is ash-chrome only")
 
-generate_grd("build_grd") {
-  grd_prefix = "ash_color_internals"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-
-  input_files = [ "index.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  # tsconfig.manifest is generated by :color_internals_ts and adds all of the
-  # in_files to the grd.
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-
-  deps = [ ":color_internals_ts" ]
-}
-
 ts_library("color_internals_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -36,3 +22,18 @@
   path_mappings =
       [ "/*|" + rebase_path("$root_gen_dir/mojom-webui/*", target_gen_dir) ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "ash_color_internals"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+
+  input_files = [ "index.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  # color_internals_ts.manifest is generated by :color_internals_ts and  adds
+  # all of the in_files to the grd.
+  manifest_files = filter_include(get_target_outputs(":color_internals_ts"),
+                                  [ "*.manifest" ])
+
+  deps = [ ":color_internals_ts" ]
+}
diff --git a/ash/webui/common/backend/plural_string_handler.cc b/ash/webui/common/backend/plural_string_handler.cc
index 1f65d96e..c56934b 100644
--- a/ash/webui/common/backend/plural_string_handler.cc
+++ b/ash/webui/common/backend/plural_string_handler.cc
@@ -17,7 +17,7 @@
 PluralStringHandler::~PluralStringHandler() = default;
 
 void PluralStringHandler::RegisterMessages() {
-  web_ui()->RegisterDeprecatedMessageCallback(
+  web_ui()->RegisterMessageCallback(
       "getPluralString",
       base::BindRepeating(&PluralStringHandler::HandleGetPluralString,
                           base::Unretained(this)));
@@ -29,12 +29,12 @@
   string_id_map_[name] = string_id;
 }
 
-void PluralStringHandler::HandleGetPluralString(const base::ListValue* args) {
+void PluralStringHandler::HandleGetPluralString(const base::Value::List& args) {
   AllowJavascript();
-  CHECK_EQ(3U, args->GetListDeprecated().size());
-  const std::string callback = args->GetListDeprecated()[0].GetString();
-  const std::string name = args->GetListDeprecated()[1].GetString();
-  const int count = args->GetListDeprecated()[2].GetInt();
+  CHECK_EQ(3U, args.size());
+  const std::string callback = args[0].GetString();
+  const std::string name = args[1].GetString();
+  const int count = args[2].GetInt();
   DCHECK(base::Contains(string_id_map_, name));
   const std::u16string localized_string =
       l10n_util::GetPluralStringFUTF16(string_id_map_.at(name), count);
diff --git a/ash/webui/common/backend/plural_string_handler.h b/ash/webui/common/backend/plural_string_handler.h
index 3a5813d..1122c3c 100644
--- a/ash/webui/common/backend/plural_string_handler.h
+++ b/ash/webui/common/backend/plural_string_handler.h
@@ -8,12 +8,9 @@
 #include <map>
 #include <string>
 
+#include "base/values.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-namespace base {
-class ListValue;
-}  // namespace base
-
 namespace ash {
 
 class PluralStringHandler : public content::WebUIMessageHandler {
@@ -35,7 +32,7 @@
 
  private:
   // Returns a localized, pluralized string.
-  void HandleGetPluralString(const base::ListValue* args);
+  void HandleGetPluralString(const base::Value::List& args);
 
   std::map<std::string, int> string_id_map_;
 };
diff --git a/ash/webui/guest_os_installer/resources/BUILD.gn b/ash/webui/guest_os_installer/resources/BUILD.gn
index fa0372cb0..b7ba399 100644
--- a/ash/webui/guest_os_installer/resources/BUILD.gn
+++ b/ash/webui/guest_os_installer/resources/BUILD.gn
@@ -91,7 +91,8 @@
   input_files_base_dir = rebase_path(".", "//")
 
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 
   grd_prefix = "ash_guest_os_installer"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
diff --git a/ash/webui/personalization_app/resources/BUILD.gn b/ash/webui/personalization_app/resources/BUILD.gn
index e413648..8e6040ca 100644
--- a/ash/webui/personalization_app/resources/BUILD.gn
+++ b/ash/webui/personalization_app/resources/BUILD.gn
@@ -254,7 +254,8 @@
         [ "personalization_app.rollup.js|trusted/personalization_app.js" ]
   } else {
     deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   }
   grd_prefix = "ash_personalization_app"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
diff --git a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
index 23b896efa..294bd5d7 100644
--- a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
+++ b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.html
@@ -66,15 +66,19 @@
     width: 24px;
   }
 
+  .dark-icon {
+    fill: var(--cros-icon-color-primary-dark);
+  }
+
+  .light-icon {
+    fill: var(--cros-icon-color-primary-light);
+  }
+
   .color-container[aria-checked='true'] .color-inner-container {
     height: 36px;
     width: 36px;
   }
 
-  .color-inner-container svg {
-    fill: var(--cros-icon-color-primary);
-  }
-
   .color-container:focus-visible {
     outline: 2px solid var(--cros-focus-ring-color);
     outline-offset: -2px;
@@ -137,7 +141,7 @@
         role="radio">
       <div class="color-inner-container"
           style$="[[getWallpaperColorInnerContainerStyle_(wallpaperColor_)]]">
-        <svg viewBox="0 0 20 20" width="16" height="16">
+        <svg class$="[[getWallpaperIconColorClass_(wallpaperColor_)]]" viewBox="0 0 20 20" width="16" height="16">
           <path fill-rule="evenodd" clip-rule="evenodd" d="M12.0605 5.585L13.5805 6.935C14.3705 7.715 14.2005 8.985 13.4105 9.765L4.76469 18.4108C3.98364 19.1918 2.71731 19.1918 1.93626 18.4108L0.583834 17.0584C-0.196879 16.2776 -0.197265 15.012 0.582974 14.2308L7.40048 7.405L9.23048 5.585C10.0105 4.805 11.2805 4.805 12.0605 5.585ZM8.82101 8.81494L1.95101 15.6849L3.36101 17.1049L10.231 10.2249L8.82101 8.81494Z">
           </path>
           <path d="M16 6L15.06 3.94L13 3L15.06 2.06L16 0L16.94 2.06L19 3L16.94 3.94L16 6Z">
diff --git a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
index 6262cf1..cca59e3 100644
--- a/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
+++ b/ash/webui/personalization_app/resources/trusted/keyboard_backlight/keyboard_backlight_element.ts
@@ -36,6 +36,17 @@
   };
 }
 
+/**
+  Based on this algorithm suggested by the W3:
+  https://www.w3.org/TR/AERT/#color-contrast
+*/
+function calculateColorBrightness(hexVal: number): number {
+  const r = (hexVal >> 16) & 0xff;  // extract red
+  const g = (hexVal >> 8) & 0xff;   // extract green
+  const b = (hexVal >> 0) & 0xff;   // extract blue
+  return (r * 299 + g * 587 + b * 114) / 1000;
+}
+
 interface ColorInfo {
   hexVal: string;
   enumVal: BacklightColor;
@@ -254,7 +265,7 @@
   private getWallpaperColorInnerContainerStyle_(wallpaperColor: SkColor):
       string {
     // Show the default style when wallpaper color is loading or invalid.
-    if (!wallpaperColor || !wallpaperColor.value) {
+    if (!wallpaperColor || (wallpaperColor.value & 0xFFFFFF) === 0xFFFFFF) {
       return `background-color: #FFFFFF;
           border: 1px solid var(--cros-separator-color);`;
     }
@@ -264,6 +275,18 @@
     return `background-color: #${hexStr};`;
   }
 
+  private getWallpaperIconColorClass_(wallpaperColor: SkColor): string {
+    if (!wallpaperColor || (wallpaperColor.value & 0xFFFFFF) === 0xFFFFFF) {
+      return `light-icon`;
+    }
+    const brightness =
+        calculateColorBrightness(wallpaperColor.value & 0xFFFFFF);
+    if (brightness < 125) {
+      return `dark-icon`;
+    }
+    return `light-icon`;
+  }
+
   private getPresetColorAriaLabel_(presetColorId: string): string {
     return this.i18n(presetColorId);
   }
diff --git a/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js b/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js
index 49963c8..30726af 100644
--- a/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js
+++ b/ash/webui/projector_app/resources/app/untrusted/untrusted_app_comm_factory.js
@@ -175,6 +175,17 @@
     return AppUntrustedCommFactory.getPostMessageAPIClient().callApiFn(
         'openFeedbackDialog', []);
   },
+
+  /**
+   * Gets information about the specified screencast from DriveFS.
+   * @param {string} screencastId The Drive item id of container folder.
+   * @return {!Promise<projectorApp.Screencast>}
+   */
+  // TODO(b/236857019) Wires up this with trusted context and message handle.
+  getScreencast(screencastId) {
+    return Promise.reject('Unsupported');
+  },
+
 };
 
 /**
diff --git a/ash/webui/projector_app/resources/communication/projector_app.externs.js b/ash/webui/projector_app/resources/communication/projector_app.externs.js
index c4c7c69..9673660 100644
--- a/ash/webui/projector_app/resources/communication/projector_app.externs.js
+++ b/ash/webui/projector_app/resources/communication/projector_app.externs.js
@@ -176,9 +176,7 @@
 /**
  * The created time of the screencast video, as the number of milliseconds since
  * the epoch.
- * TODO(b/215258794): After adding |createdTime| on Chromium side, remove the
- * 'undefined' from type definition.
- * @type {number|undefined}
+ * @type {number}
  */
 projectorApp.PendingScreencast.prototype.createdTime;
 
@@ -238,6 +236,48 @@
 projectorApp.NewScreencastPreconditionState.prototype.reasons;
 
 /**
+ * Structure for Screencast video object.
+ * @record
+ * @struct
+ */
+projectorApp.Video = function() {};
+
+/**
+ * The local source url of screencast video.
+ * @type {string|undefined}
+ */
+projectorApp.Video.prototype.srcURL;
+
+/**
+ * Structure for Screencast object.
+ * @record
+ * @struct
+ */
+projectorApp.Screencast = function() {};
+
+/**
+ * The container folder id of the screencast.
+ * @type {string}
+ */
+// TODO(b/236858194): Add the rest of the fields and refactor the Screencast
+// model in ../shared/screencast_model.d.ts to this file. Remove
+// PendingScreencast.
+projectorApp.Screencast.prototype.containerFolderId;
+
+/**
+ * The name of the screencast.
+ * @type {string}
+ */
+projectorApp.Screencast.prototype.name;
+
+
+/**
+ * The video object of screencast.
+ * @type {projectorApp.Video}
+ */
+projectorApp.Screencast.prototype.video;
+
+/**
  * The delegate interface that the Projector app can use to make requests to
  * chrome.
  * @record
@@ -296,7 +336,7 @@
  * @param {string} method the request method.
  * @param {string=} requestBody the request body data.
  * @param {boolean=} useCredentials authorize the request with end user
- *      credentials. Used for getting streaming URL.
+ *  credentials. Used for getting streaming URL.
  * @param {Object=} additional headers.
  * @return {!Promise<!projectorApp.XhrResponse>}
  */
@@ -344,6 +384,16 @@
  */
 projectorApp.ClientDelegate.prototype.openFeedbackDialog = function() {};
 
+// TODO(b/236860361): Support screencast located outside DriveFS by using path
+// or blob uuid.
+
+/**
+ * Gets information about the specified screencast from DriveFS.
+ * @param {string} screencastId The Drive item id of container folder.
+ * @return {!Promise<projectorApp.Screencast>}
+ */
+projectorApp.ClientDelegate.prototype.getScreencast = function(screencastId) {};
+
 /**
  * The client Api for interacting with the Projector app instance.
  * @record
@@ -372,6 +422,9 @@
  */
 projectorApp.AppApi.prototype.setClientDelegate = function(clientDelegate) {};
 
+// TODO(b/224705800): Don't notify the Projector client for SODA installation
+// progress updates. This number is no longer surfaced in the UI, so the
+// wiring can be cleaned up.
 /**
  * Notifies the Projector App the download and installation progress of the SODA
  * binary and language packs.
@@ -389,4 +442,4 @@
 /**
  * Notifies the Projector App when there is a SODA installation error.
  */
-projectorApp.AppApi.prototype.onSodaInstallError = function() {};
\ No newline at end of file
+projectorApp.AppApi.prototype.onSodaInstallError = function() {};
diff --git a/ash/webui/sample_system_web_app_ui/resources/trusted/BUILD.gn b/ash/webui/sample_system_web_app_ui/resources/trusted/BUILD.gn
index d707ba22..0d369ce7 100644
--- a/ash/webui/sample_system_web_app_ui/resources/trusted/BUILD.gn
+++ b/ash/webui/sample_system_web_app_ui/resources/trusted/BUILD.gn
@@ -10,6 +10,31 @@
 assert(!is_official_build,
        "Sample System Web App is only built for unofficial builds")
 
+ts_library("trusted_ts") {
+  root_dir = "."
+  out_dir = "$target_gen_dir/tsc"
+
+  in_files = [
+    "inter_frame_communication.ts",
+    "main.ts",
+    "page_handler.ts",
+
+    # TODO(crbug.com/1002798): Migrate these Shared Worker files to TS.
+    "timer.js",
+    "worker.js",
+  ]
+
+  tsconfig_base = "../../tsconfig_base.json"
+  composite = true
+
+  # Allows TSC to check the generated mojom-webui/ directory when it encounters
+  # imports.
+  path_mappings =
+      [ "/*|" + rebase_path("$root_gen_dir/mojom-webui/*", target_gen_dir) ]
+
+  deps = [ "../../mojom:mojom_ts" ]
+}
+
 generate_grd("trusted_grd") {
   # Note: Don't forget to:
   #
@@ -34,9 +59,10 @@
   ]
   input_files_base_dir = rebase_path(".", "//")
 
-  # tsconfig.manifest is generated by :trusted_ts and adds all of the
-  # in_files to the grd.
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  # trusted_ts.manifest is generated by :trusted_ts and adds all of the in_files
+  # to the grd.
+  manifest_files =
+      filter_include(get_target_outputs(":trusted_ts"), [ "*.manifest" ])
 
   # Flatten out the dependency tree of your mojom and add generated bindings
   # grdp files here.
@@ -54,28 +80,3 @@
     "../../mojom:trusted_webui_grdp",
   ]
 }
-
-ts_library("trusted_ts") {
-  root_dir = "."
-  out_dir = "$target_gen_dir/tsc"
-
-  in_files = [
-    "inter_frame_communication.ts",
-    "main.ts",
-    "page_handler.ts",
-
-    # TODO(crbug.com/1002798): Migrate these Shared Worker files to TS.
-    "timer.js",
-    "worker.js",
-  ]
-
-  tsconfig_base = "../../tsconfig_base.json"
-  composite = true
-
-  # Allows TSC to check the generated mojom-webui/ directory when it encounters
-  # imports.
-  path_mappings =
-      [ "/*|" + rebase_path("$root_gen_dir/mojom-webui/*", target_gen_dir) ]
-
-  deps = [ "../../mojom:mojom_ts" ]
-}
diff --git a/ash/webui/sample_system_web_app_ui/resources/untrusted/BUILD.gn b/ash/webui/sample_system_web_app_ui/resources/untrusted/BUILD.gn
index 75bc7ad..1d40e24 100644
--- a/ash/webui/sample_system_web_app_ui/resources/untrusted/BUILD.gn
+++ b/ash/webui/sample_system_web_app_ui/resources/untrusted/BUILD.gn
@@ -10,43 +10,6 @@
 assert(!is_official_build,
        "Sample System Web App is only built for unofficial builds")
 
-generate_grd("untrusted_grd") {
-  # Note: Don't forget to:
-  #
-  #  1. Allocate resource id in //tools/gritsettings/resource_ids.spec for the
-  #     .grd file
-  #  2. Generate the resource pack (a .pak file) from the .grd file generated
-  #     here in //ash/webui/resources/BUILD.gn
-  #  3. Add the generated pack (from step 1) to //chrome/chrome_paks.gni
-  #
-  # Otherwise you'll see network errors when loading the resources.
-  grd_prefix = "ash_sample_system_web_app_untrusted"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-
-  input_files = [ "untrusted.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  # tsconfig.manifest is generated by :untrusted_ts and adds all of the
-  # in_files to the grd.
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-
-  # Flatten out the dependency tree of your mojom and add generated bindings
-  # grdp files here.
-  # TODO(crbug.com/1002798): We could add a mojo_grdp_deps variable to
-  # generate_grd that automatically adds these grdp files when you add a
-  # X_webui_grdp target to it.
-  grdp_files = [
-    "$target_gen_dir/../../mojom/shared_webui_resources.grdp",
-    "$target_gen_dir/../../mojom/untrusted_webui_resources.grdp",
-  ]
-
-  deps = [
-    ":untrusted_ts",
-    "../../mojom:shared_webui_grdp",
-    "../../mojom:untrusted_webui_grdp",
-  ]
-}
-
 ts_library("untrusted_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -66,3 +29,41 @@
 
   deps = [ "../../mojom:mojom_ts" ]
 }
+
+generate_grd("untrusted_grd") {
+  # Note: Don't forget to:
+  #
+  #  1. Allocate resource id in //tools/gritsettings/resource_ids.spec for the
+  #     .grd file
+  #  2. Generate the resource pack (a .pak file) from the .grd file generated
+  #     here in //ash/webui/resources/BUILD.gn
+  #  3. Add the generated pack (from step 1) to //chrome/chrome_paks.gni
+  #
+  # Otherwise you'll see network errors when loading the resources.
+  grd_prefix = "ash_sample_system_web_app_untrusted"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+
+  input_files = [ "untrusted.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  # untrusted_ts.manifest is generated by :untrusted_ts and adds all of the
+  # in_files to the grd.
+  manifest_files =
+      filter_include(get_target_outputs(":untrusted_ts"), [ "*.manifest" ])
+
+  # Flatten out the dependency tree of your mojom and add generated bindings
+  # grdp files here.
+  # TODO(crbug.com/1002798): We could add a mojo_grdp_deps variable to
+  # generate_grd that automatically adds these grdp files when you add a
+  # X_webui_grdp target to it.
+  grdp_files = [
+    "$target_gen_dir/../../mojom/shared_webui_resources.grdp",
+    "$target_gen_dir/../../mojom/untrusted_webui_resources.grdp",
+  ]
+
+  deps = [
+    ":untrusted_ts",
+    "../../mojom:shared_webui_grdp",
+    "../../mojom:untrusted_webui_grdp",
+  ]
+}
diff --git a/base/big_endian.h b/base/big_endian.h
index f288ffd..a904ced7 100644
--- a/base/big_endian.h
+++ b/base/big_endian.h
@@ -137,8 +137,9 @@
   template<typename T>
   bool Write(T v);
 
-  raw_ptr<char, DanglingUntriaged> ptr_;
-  raw_ptr<char, DanglingUntriaged> end_;
+  // TODO(crbug.com/1298696): Breaks net_unittests.
+  raw_ptr<char, DanglingUntriagedDegradeToNoOpWhenMTE> ptr_;
+  raw_ptr<char, DanglingUntriagedDegradeToNoOpWhenMTE> end_;
 };
 
 }  // namespace base
diff --git a/base/files/file_descriptor_watcher_posix.h b/base/files/file_descriptor_watcher_posix.h
index b212e749..e7edae0 100644
--- a/base/files/file_descriptor_watcher_posix.h
+++ b/base/files/file_descriptor_watcher_posix.h
@@ -75,7 +75,9 @@
     // Controller is deleted, ownership of |watcher_| is transfered to a delete
     // task posted to the MessageLoopForIO. This ensures that |watcher_| isn't
     // deleted while it is being used by the MessageLoopForIO.
-    raw_ptr<Watcher, DanglingUntriaged> watcher_;
+    //
+    // TODO(crbug.com/1298696): Breaks base_unittests.
+    raw_ptr<Watcher, DanglingUntriagedDegradeToNoOpWhenMTE> watcher_;
 
     // An event for the watcher to notify controller that it's destroyed.
     // As the |watcher_| is owned by Controller, always outlives the Watcher.
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
index a065874..b6246cf 100644
--- a/base/files/memory_mapped_file.h
+++ b/base/files/memory_mapped_file.h
@@ -139,7 +139,8 @@
   void CloseHandles();
 
   File file_;
-  raw_ptr<uint8_t> data_;
+  // TODO(crbug.com/1298696): Breaks one of the test suites.
+  raw_ptr<uint8_t, DegradeToNoOpWhenMTE> data_;
   size_t length_;
 
 #if BUILDFLAG(IS_WIN)
diff --git a/base/memory/raw_ptr.h b/base/memory/raw_ptr.h
index 7a2c89d9..10f808c 100644
--- a/base/memory/raw_ptr.h
+++ b/base/memory/raw_ptr.h
@@ -1132,6 +1132,42 @@
 // occurrences are meant to be removed.
 using DanglingUntriaged = DisableDanglingPtrDetection;
 
+// The following template parameters are only meaningful when `raw_ptr`
+// is `MTECheckedPtr` (never the case unless a particular GN arg is set
+// true.) `raw_ptr` users need not worry about this and can refer solely
+// to `DisableDanglingPtrDetection` and `DanglingUntriaged` above.
+//
+// The `raw_ptr` definition allows users to specify an implementation.
+// When `MTECheckedPtr` is in play, we need to augment this
+// implementation setting with another layer that allows the `raw_ptr`
+// to degrade into the no-op version.
+#if defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+
+// Direct pass-through to no-op implementation.
+using DegradeToNoOpWhenMTE = base::internal::RawPtrNoOpImpl;
+
+// As above, but with the "untriaged dangling" annotation.
+using DanglingUntriagedDegradeToNoOpWhenMTE = base::internal::RawPtrNoOpImpl;
+
+// As above, but with the "explicitly disable protection" annotation.
+using DisableDanglingPtrDetectionDegradeToNoOpWhenMTE =
+    base::internal::RawPtrNoOpImpl;
+
+#else
+
+// Direct pass-through to default implementation specified by `raw_ptr`
+// template.
+using DegradeToNoOpWhenMTE = base::RawPtrBanDanglingIfSupported;
+
+// Direct pass-through to `DanglingUntriaged`.
+using DanglingUntriagedDegradeToNoOpWhenMTE = DanglingUntriaged;
+
+// Direct pass-through to `DisableDanglingPtrDetection`.
+using DisableDanglingPtrDetectionDegradeToNoOpWhenMTE =
+    DisableDanglingPtrDetection;
+
+#endif  // defined(PA_USE_MTE_CHECKED_PTR_WITH_64_BITS_POINTERS)
+
 namespace std {
 
 // Override so set/map lookups do not create extra raw_ptr. This also allows
diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h
index a9be977..a57da89 100644
--- a/base/synchronization/waitable_event_watcher.h
+++ b/base/synchronization/waitable_event_watcher.h
@@ -145,7 +145,9 @@
   scoped_refptr<Flag> cancel_flag_;
 
   // Enqueued in the wait list of the watched WaitableEvent.
-  raw_ptr<AsyncWaiter, DanglingUntriaged> waiter_ = nullptr;
+  //
+  // TODO(crbug.com/1298696): Breaks base_unittests.
+  raw_ptr<AsyncWaiter, DanglingUntriagedDegradeToNoOpWhenMTE> waiter_ = nullptr;
 
   // Kernel of the watched WaitableEvent.
   scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
diff --git a/build/fuchsia/linux_internal.sdk.sha1 b/build/fuchsia/linux_internal.sdk.sha1
index dd63d2fb..d48d7cb 100644
--- a/build/fuchsia/linux_internal.sdk.sha1
+++ b/build/fuchsia/linux_internal.sdk.sha1
@@ -1 +1 @@
-8.20220630.0.1
+8.20220701.0.1
diff --git a/cc/test/test_layer_tree_frame_sink.cc b/cc/test/test_layer_tree_frame_sink.cc
index 2c0a77c..e28b97f7 100644
--- a/cc/test/test_layer_tree_frame_sink.cc
+++ b/cc/test/test_layer_tree_frame_sink.cc
@@ -143,6 +143,14 @@
   return true;
 }
 
+void TestLayerTreeFrameSink::UnregisterBeginFrameSource() {
+  if (display_begin_frame_source_) {
+    frame_sink_manager_->UnregisterBeginFrameSource(
+        display_begin_frame_source_);
+    display_begin_frame_source_ = nullptr;
+  }
+}
+
 void TestLayerTreeFrameSink::DetachFromClient() {
   // This acts like the |shared_bitmap_manager_| is a global object, while
   // in fact it is tied to the lifetime of this class and is destroyed below:
@@ -262,6 +270,10 @@
   client_->ReclaimResources(std::move(resources));
 }
 
+void TestLayerTreeFrameSink::OnBeginFramePausedChanged(bool paused) {
+  external_begin_frame_source_.OnSetBeginFrameSourcePaused(paused);
+}
+
 void TestLayerTreeFrameSink::DisplayOutputSurfaceLost() {
   DebugScopedSetImplThread impl(task_runner_provider_);
   client_->DidLoseLayerTreeFrameSink();
diff --git a/cc/test/test_layer_tree_frame_sink.h b/cc/test/test_layer_tree_frame_sink.h
index 41d1263..be5155f 100644
--- a/cc/test/test_layer_tree_frame_sink.h
+++ b/cc/test/test_layer_tree_frame_sink.h
@@ -87,6 +87,7 @@
   void SetDisplayColorSpace(const gfx::ColorSpace& output_color_space);
 
   viz::Display* display() const { return display_.get(); }
+  void UnregisterBeginFrameSource();
 
   // LayerTreeFrameSink implementation.
   bool BindToClient(LayerTreeFrameSinkClient* client) override;
@@ -106,7 +107,7 @@
   void OnBeginFrame(const viz::BeginFrameArgs& args,
                     const viz::FrameTimingDetailsMap& timing_details) override;
   void ReclaimResources(std::vector<viz::ReturnedResource> resources) override;
-  void OnBeginFramePausedChanged(bool paused) override {}
+  void OnBeginFramePausedChanged(bool paused) override;
   void OnCompositorFrameTransitionDirectiveProcessed(
       uint32_t sequence_id) override {}
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index d1d52c7..ff79dd0 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -10402,5 +10402,82 @@
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestDidCommitAndDrawFrame);
+
+class LayerTreeHostTestBeginFramePausedChanged : public LayerTreeHostTest {
+ protected:
+  void SetupTree() override {
+    scoped_refptr<Layer> root = Layer::Create();
+    root->SetBounds(gfx::Size(10, 10));
+    layer_tree_host()->SetRootLayer(std::move(root));
+    LayerTreeHostTest::SetupTree();
+  }
+
+  void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+  void ReadyToCommitOnThread(LayerTreeHostImpl* host_impl) override {
+    switch (host_impl->active_tree()->source_frame_number()) {
+      // frame 1 is ready in main thread and main thread is waiting until
+      // commit complete in impl thread
+      case 0:
+        // this should trigger OnBeginFramePausedChanged(true) callback, so that
+        // scheduler can abort the pending commit job
+        layer_tree_frame_sink_->UnregisterBeginFrameSource();
+        break;
+    }
+  }
+
+  void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+    switch (host_impl->pending_tree()->source_frame_number()) {
+      case 1:
+        // Scheduler abort the pending commit job successfully
+        EndTest();
+        break;
+    }
+  }
+
+  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+    switch (host_impl->active_tree()->source_frame_number()) {
+      case 0:
+        // Block activation of pedning tree which is created by implside
+        // invalidation. This is for making ShouldCommit() return false.
+        host_impl->BlockNotifyReadyToActivateForTesting(true);
+        // next commit can start only if pending tree was created by implside
+        // invalidation.
+        host_impl->RequestImplSideInvalidationForRerasterTiling();
+        break;
+    }
+  }
+
+  void DidInvalidateContentOnImplSide(LayerTreeHostImpl* host_impl) override {
+    switch (host_impl->active_tree()->source_frame_number()) {
+      case 0:
+        // has_pending_tree_ is true now, so we can request next frame which
+        // will be stuck in main thread because has_pending_tree_ == true block
+        // commit process.
+        PostSetNeedsCommitToMainThread();
+        break;
+    }
+  }
+
+  std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
+      const viz::RendererSettings& renderer_settings,
+      double refresh_rate,
+      scoped_refptr<viz::ContextProvider> compositor_context_provider,
+      scoped_refptr<viz::RasterContextProvider> worker_context_provider)
+      override {
+    std::unique_ptr<TestLayerTreeFrameSink> frame_sink =
+        LayerTreeHostTest::CreateLayerTreeFrameSink(
+            renderer_settings, refresh_rate,
+            std::move(compositor_context_provider),
+            std::move(worker_context_provider));
+    layer_tree_frame_sink_ = frame_sink.get();
+    return frame_sink;
+  }
+
+ private:
+  TestLayerTreeFrameSink* layer_tree_frame_sink_;
+};
+MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFramePausedChanged);
+
 }  // namespace
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index 1cbf844..4af8e55 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=105
 MINOR=0
-BUILD=5153
+BUILD=5154
 PATCH=0
diff --git a/chrome/android/expectations/monochrome_public_bundle__autofill_assistant.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle__autofill_assistant.AndroidManifest.expected
index 8b0de02..08d1809 100644
--- a/chrome/android/expectations/monochrome_public_bundle__autofill_assistant.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle__autofill_assistant.AndroidManifest.expected
@@ -6,21 +6,17 @@
     package="org.chromium.chrome.stable"
     platformBuildVersionCode="31"
     platformBuildVersionName="12">
-  <dist:module dist:title="@string/autofill_assistant_module_title">  # DIFF-ANCHOR: afa8402d
-    <dist:delivery>  # DIFF-ANCHOR: f7518c58
-      <dist:install-time>  # DIFF-ANCHOR: 4387071b
-        <dist:conditions>  # DIFF-ANCHOR: 210b2aff
+  <dist:module dist:title="@string/autofill_assistant_module_title">  # DIFF-ANCHOR: 328f25a9
+    <dist:delivery>  # DIFF-ANCHOR: 62b39bbe
+      <dist:install-time>  # DIFF-ANCHOR: a4752ed3
+        <dist:conditions>  # DIFF-ANCHOR: bedacbe5
           <dist:min-sdk dist:value="26"/>
-          <dist:user-countries dist:include="true">  # DIFF-ANCHOR: 285b35e4
-            <dist:country dist:code="GB"/>
-            <dist:country dist:code="US"/>
-          </dist:user-countries>  # DIFF-ANCHOR: 285b35e4
-        </dist:conditions>  # DIFF-ANCHOR: 210b2aff
-      </dist:install-time>  # DIFF-ANCHOR: 4387071b
+        </dist:conditions>  # DIFF-ANCHOR: bedacbe5
+      </dist:install-time>  # DIFF-ANCHOR: a4752ed3
       <dist:on-demand/>
-    </dist:delivery>  # DIFF-ANCHOR: f7518c58
+    </dist:delivery>  # DIFF-ANCHOR: 62b39bbe
     <dist:fusing dist:include="true"/>
-  </dist:module>  # DIFF-ANCHOR: afa8402d
+  </dist:module>  # DIFF-ANCHOR: 328f25a9
   <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="31"/>
   <uses-split android:name="chrome"/>
   <application/>
diff --git a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
index 395b4ff..17f6715 100644
--- a/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
+++ b/chrome/android/features/autofill_assistant/java/AndroidManifest.xml
@@ -10,10 +10,6 @@
           <dist:install-time>
             <dist:conditions>
               <dist:min-sdk dist:value="26"/>
-              <dist:user-countries dist:include="true">
-                <dist:country dist:code="US"/>
-                <dist:country dist:code="GB"/>
-              </dist:user-countries>
             </dist:conditions>
           </dist:install-time>
         </dist:delivery>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 988fd13..3811f35 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1218,6 +1218,12 @@
     "policy/schema_registry_service.h",
     "policy/schema_registry_service_builder.cc",
     "policy/schema_registry_service_builder.h",
+    "policy/status_provider/cloud_policy_core_status_provider.cc",
+    "policy/status_provider/cloud_policy_core_status_provider.h",
+    "policy/status_provider/status_provider_util.cc",
+    "policy/status_provider/status_provider_util.h",
+    "policy/status_provider/user_cloud_policy_status_provider.cc",
+    "policy/status_provider/user_cloud_policy_status_provider.h",
     "policy/webusb_allow_devices_for_urls_policy_handler.cc",
     "policy/webusb_allow_devices_for_urls_policy_handler.h",
     "predictors/autocomplete_action_predictor.cc",
@@ -4023,8 +4029,6 @@
       "policy/webhid_device_policy_handler.h",
       "prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper.cc",
       "prefetch/zero_suggest_prefetch/zero_suggest_prefetch_tab_helper.h",
-      "privacy_sandbox/generated_floc_pref.cc",
-      "privacy_sandbox/generated_floc_pref.h",
       "process_singleton_modal_dialog_lock.cc",
       "process_singleton_modal_dialog_lock.h",
       "process_singleton_startup_lock.cc",
@@ -4930,6 +4934,16 @@
       "platform_util_ash.cc",
       "policy/default_geolocation_policy_handler.cc",
       "policy/default_geolocation_policy_handler.h",
+      "policy/status_provider/device_active_directory_policy_status_provider.cc",
+      "policy/status_provider/device_active_directory_policy_status_provider.h",
+      "policy/status_provider/device_cloud_policy_status_provider_chromeos.cc",
+      "policy/status_provider/device_cloud_policy_status_provider_chromeos.h",
+      "policy/status_provider/device_local_account_policy_status_provider.cc",
+      "policy/status_provider/device_local_account_policy_status_provider.h",
+      "policy/status_provider/user_active_directory_policy_status_provider.cc",
+      "policy/status_provider/user_active_directory_policy_status_provider.h",
+      "policy/status_provider/user_cloud_policy_status_provider_chromeos.cc",
+      "policy/status_provider/user_cloud_policy_status_provider_chromeos.h",
       "resource_coordinator/tab_manager_delegate_chromeos.cc",
       "resource_coordinator/tab_manager_delegate_chromeos.h",
       "sharesheet/share_action/example_action.cc",
@@ -5473,6 +5487,10 @@
       "notifications/notification_platform_bridge_lacros.cc",
       "notifications/notification_platform_bridge_lacros.h",
       "platform_util_lacros.cc",
+      "policy/status_provider/device_policy_status_provider_lacros.cc",
+      "policy/status_provider/device_policy_status_provider_lacros.h",
+      "policy/status_provider/user_policy_status_provider_lacros.cc",
+      "policy/status_provider/user_policy_status_provider_lacros.h",
       "signin/signin_ui_delegate_impl_lacros.cc",
       "signin/signin_ui_delegate_impl_lacros.h",
       "speech/tts_client_factory_lacros.cc",
@@ -5923,6 +5941,8 @@
         "google/google_update_win.h",
         "google/switches.cc",
         "google/switches.h",
+        "policy/status_provider/updater_status_provider.cc",
+        "policy/status_provider/updater_status_provider.h",
         "win/conflicts/incompatible_applications_updater.cc",
         "win/conflicts/incompatible_applications_updater.h",
         "win/conflicts/installed_applications.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 0ebc891..eaf69de 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -54,6 +54,7 @@
 #include "chrome/browser/share/share_features.h"
 #include "chrome/browser/sharing/features.h"
 #include "chrome/browser/sharing_hub/sharing_hub_features.h"
+#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/site_isolation/about_flags.h"
 #include "chrome/browser/ui/app_list/search/search_features.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
@@ -1372,26 +1373,38 @@
         {"10 suggestions if 2 or fewer URLs", kOmniboxDynamicMaxAutocomplete102,
          std::size(kOmniboxDynamicMaxAutocomplete102), nullptr}};
 
-const FeatureEntry::FeatureParam kFiveOrganicRepeatableQueries[] = {
-    {"MaxNumRepeatableQueries", "5"}};
-const FeatureEntry::FeatureParam kFiveOrganicRepeatableQueriesScaled[] = {
-    {"MaxNumRepeatableQueries", "5"},
-    {"ScaleRepeatableQueriesScores", "true"}};
 const FeatureEntry::FeatureParam
-    kFiveOrganicRepeatableQueriesScaledPrivileged[] = {
-        {"MaxNumRepeatableQueries", "5"},
+    kOrganicRepeatableQueriesCappedWithHighPrivilege[] = {
+        {"MaxNumRepeatableQueries", "4"},
         {"ScaleRepeatableQueriesScores", "true"},
         {"PrivilegeRepeatableQueries", "true"}};
+const FeatureEntry::FeatureParam
+    kOrganicRepeatableQueriesCappedWithLowPrivilege[] = {
+        {"MaxNumRepeatableQueries", "4"},
+        {"ScaleRepeatableQueriesScores", "true"},
+        {"PrivilegeRepeatableQueries", "false"}};
+const FeatureEntry::FeatureParam
+    kOrganicRepeatableQueriesUncappedWithHighPrivilege[] = {
+        {"ScaleRepeatableQueriesScores", "true"},
+        {"PrivilegeRepeatableQueries", "true"}};
+const FeatureEntry::FeatureParam
+    kOrganicRepeatableQueriesUncappedWithLowPrivilege[] = {
+        {"ScaleRepeatableQueriesScores", "true"},
+        {"PrivilegeRepeatableQueries", "false"}};
 
 const FeatureEntry::FeatureVariation kOrganicRepeatableQueriesVariations[] = {
-    {"- up to 5 repeatable queries", kFiveOrganicRepeatableQueries,
-     std::size(kFiveOrganicRepeatableQueries), nullptr},
-    {"- up to 5 repeatable queries - scaled for mixing",
-     kFiveOrganicRepeatableQueriesScaled,
-     std::size(kFiveOrganicRepeatableQueriesScaled), nullptr},
-    {"- up to 5 repeatable queries - scaled and privileged for mixing",
-     kFiveOrganicRepeatableQueriesScaledPrivileged,
-     std::size(kFiveOrganicRepeatableQueriesScaledPrivileged), nullptr}};
+    {"- No max, High privilege",
+     kOrganicRepeatableQueriesUncappedWithHighPrivilege,
+     std::size(kOrganicRepeatableQueriesUncappedWithHighPrivilege), nullptr},
+    {"- No max, Low privilege",
+     kOrganicRepeatableQueriesUncappedWithLowPrivilege,
+     std::size(kOrganicRepeatableQueriesUncappedWithLowPrivilege), nullptr},
+    {"- Max 4, High privilege",
+     kOrganicRepeatableQueriesCappedWithHighPrivilege,
+     std::size(kOrganicRepeatableQueriesCappedWithHighPrivilege), nullptr},
+    {"- Max 4, Low privilege", kOrganicRepeatableQueriesCappedWithLowPrivilege,
+     std::size(kOrganicRepeatableQueriesCappedWithLowPrivilege), nullptr},
+};
 
 const FeatureEntry::FeatureParam kMinimumTabWidthSettingPinned[] = {
     {features::kMinimumTabWidthFeatureParameterName, "54"}};
@@ -4808,6 +4821,11 @@
      flag_descriptions::kEnableAutofillRefreshStyleName,
      flag_descriptions::kEnableAutofillRefreshStyleDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillRefreshStyleAndroid)},
+
+    {"enable-family-info-feedback",
+     flag_descriptions::kEnableFamilyInfoFeedbackName,
+     flag_descriptions::kEnableFamilyInfoFeedbackDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(kEnableFamilyInfoFeedback)},
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/apps/app_service/launch_utils.cc b/chrome/browser/apps/app_service/launch_utils.cc
index a326bdc..7913d042 100644
--- a/chrome/browser/apps/app_service/launch_utils.cc
+++ b/chrome/browser/apps/app_service/launch_utils.cc
@@ -310,9 +310,7 @@
   }
 }
 
-int GetEventFlags(apps::mojom::LaunchContainer container,
-                  WindowOpenDisposition disposition,
-                  bool prefer_container) {
+int GetEventFlags(WindowOpenDisposition disposition, bool prefer_container) {
   if (prefer_container) {
     return ui::EF_NONE;
   }
diff --git a/chrome/browser/apps/app_service/launch_utils.h b/chrome/browser/apps/app_service/launch_utils.h
index 2b77d20..8d3da55 100644
--- a/chrome/browser/apps/app_service/launch_utils.h
+++ b/chrome/browser/apps/app_service/launch_utils.h
@@ -70,12 +70,10 @@
 extensions::AppLaunchSource GetAppLaunchSource(
     apps::mojom::LaunchSource launch_source);
 
-// Returns event flag for |container| and |disposition|. If |prefer_container|
-// is true, |disposition| will be ignored. Otherwise, |container| is ignored and
-// an event flag based on |disposition| will be returned.
-int GetEventFlags(apps::mojom::LaunchContainer container,
-                  WindowOpenDisposition disposition,
-                  bool prefer_container);
+// Returns event flag for |disposition|. If |prefer_container|
+// is true, |disposition| will be ignored. Otherwise, an event flag based on
+// |disposition| will be returned.
+int GetEventFlags(WindowOpenDisposition disposition, bool prefer_container);
 
 // Returns the browser's session id for restoration if |web_contents| is valid
 // for a system web app, or for a web app not opened in tab. Otherwise, returns
diff --git a/chrome/browser/apps/app_service/launch_utils_unittest.cc b/chrome/browser/apps/app_service/launch_utils_unittest.cc
index dc4a9af6..b834522 100644
--- a/chrome/browser/apps/app_service/launch_utils_unittest.cc
+++ b/chrome/browser/apps/app_service/launch_utils_unittest.cc
@@ -28,8 +28,7 @@
       apps::mojom::LaunchContainer fallback_container =
           apps::mojom::LaunchContainer::kLaunchContainerNone) {
     return apps::CreateAppIdLaunchParamsWithEventFlags(
-        app_id,
-        apps::GetEventFlags(container, disposition, preferred_container),
+        app_id, apps::GetEventFlags(disposition, preferred_container),
         apps::mojom::LaunchSource::kFromChromeInternal, display_id,
         fallback_container);
   }
@@ -93,14 +92,13 @@
 }
 
 TEST_F(LaunchUtilsTest, UseIntentFullUrlInLaunchParams) {
-  auto container = apps::mojom::LaunchContainer::kLaunchContainerNone;
   auto disposition = WindowOpenDisposition::NEW_WINDOW;
 
   const GURL url = GURL("https://example.com/?query=1#frag");
   auto intent = apps_util::CreateIntentFromUrl(url);
 
   auto params = apps::CreateAppLaunchParamsForIntent(
-      app_id, apps::GetEventFlags(container, disposition, true),
+      app_id, apps::GetEventFlags(disposition, true),
       apps::mojom::LaunchSource::kFromChromeInternal,
       display::kInvalidDisplayId,
       apps::mojom::LaunchContainer::kLaunchContainerWindow, std::move(intent),
@@ -110,7 +108,6 @@
 }
 
 TEST_F(LaunchUtilsTest, IntentFilesAreCopiedToLaunchParams) {
-  auto container = apps::mojom::LaunchContainer::kLaunchContainerNone;
   auto disposition = WindowOpenDisposition::NEW_WINDOW;
 
   std::vector<apps::mojom::IntentFilePtr> files;
@@ -123,7 +120,7 @@
   auto intent = apps_util::CreateViewIntentFromFiles(std::move(files));
 
   auto params = apps::CreateAppLaunchParamsForIntent(
-      app_id, apps::GetEventFlags(container, disposition, true),
+      app_id, apps::GetEventFlags(disposition, true),
       apps::mojom::LaunchSource::kFromChromeInternal,
       display::kInvalidDisplayId,
       apps::mojom::LaunchContainer::kLaunchContainerWindow, std::move(intent),
diff --git a/chrome/browser/apps/app_service/publishers/arc_apps.cc b/chrome/browser/apps/app_service/publishers/arc_apps.cc
index 79252db..8ac01b6 100644
--- a/chrome/browser/apps/app_service/publishers/arc_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/arc_apps.cc
@@ -704,7 +704,7 @@
 
 void ArcApps::LaunchAppWithParams(AppLaunchParams&& params,
                                   LaunchCallback callback) {
-  auto event_flags = apps::GetEventFlags(params.container, params.disposition,
+  auto event_flags = apps::GetEventFlags(params.disposition,
                                          /*prefer_container=*/false);
   auto window_info = apps::MakeWindowInfo(params.display_id);
   if (params.intent) {
diff --git a/chrome/browser/apps/app_service/publishers/crostini_apps.cc b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
index 92786cc..8e168c6c 100644
--- a/chrome/browser/apps/app_service/publishers/crostini_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/crostini_apps.cc
@@ -111,7 +111,7 @@
 
 void CrostiniApps::LaunchAppWithParams(AppLaunchParams&& params,
                                        LaunchCallback callback) {
-  auto event_flags = apps::GetEventFlags(params.container, params.disposition,
+  auto event_flags = apps::GetEventFlags(params.disposition,
                                          /*prefer_container=*/false);
   auto window_info = apps::MakeWindowInfo(params.display_id);
   if (params.intent) {
diff --git a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
index abde82b..8dafda0 100644
--- a/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/publishers/extension_apps_chromeos.cc
@@ -202,7 +202,7 @@
   } else {
     DCHECK(extension->is_extension());
     // TODO(petermarshall): Set Arc flag as above?
-    auto event_flags = apps::GetEventFlags(params.container, params.disposition,
+    auto event_flags = apps::GetEventFlags(params.disposition,
                                            /*prefer_container=*/false);
     auto window_info = apps::MakeWindowInfo(params.display_id);
     LaunchExtension(
diff --git a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
index 1f2ca25..ce77d86 100644
--- a/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
+++ b/chrome/browser/apps/intent_helper/chromeos_intent_picker_helpers.cc
@@ -223,12 +223,11 @@
   } else {
     // TODO(crbug.com/853604): Distinguish the source from link and omnibox.
     mojom::LaunchSource launch_source = mojom::LaunchSource::kFromLink;
-    proxy->LaunchAppWithUrl(
-        launch_name,
-        GetEventFlags(mojom::LaunchContainer::kLaunchContainerWindow,
-                      WindowOpenDisposition::NEW_WINDOW,
-                      /*prefer_container=*/true),
-        url, launch_source, apps::MakeWindowInfo(display::kDefaultDisplayId));
+    proxy->LaunchAppWithUrl(launch_name,
+                            GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                          /*prefer_container=*/true),
+                            url, launch_source,
+                            apps::MakeWindowInfo(display::kDefaultDisplayId));
     CloseOrGoBack(web_contents);
   }
 }
diff --git a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc
index c6e38a9..99870ff 100644
--- a/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc
+++ b/chrome/browser/apps/intent_helper/common_apps_navigation_throttle.cc
@@ -248,13 +248,11 @@
                            : apps::mojom::LaunchSource::kFromOmnibox;
   GURL redirected_url =
       RedirectUrlIfSwa(profile, preferred_app_id.value(), url, clock_);
-  proxy->LaunchAppWithUrl(
-      preferred_app_id.value(),
-      GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                    WindowOpenDisposition::NEW_WINDOW,
-                    /*prefer_container=*/true),
-      redirected_url, launch_source,
-      apps::MakeWindowInfo(display::kDefaultDisplayId));
+  proxy->LaunchAppWithUrl(preferred_app_id.value(),
+                          GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                        /*prefer_container=*/true),
+                          redirected_url, launch_source,
+                          apps::MakeWindowInfo(display::kDefaultDisplayId));
 
   const GURL& last_committed_url = web_contents->GetLastCommittedURL();
   if (!last_committed_url.is_valid() || last_committed_url.IsAboutBlank() ||
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index e9c05c52..88d4fd2f 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -248,10 +248,8 @@
     apps::AppServiceProxyFactory::GetForProfile(browser()->profile())
         ->LaunchAppWithFiles(
             extension->id(),
-            apps::GetEventFlags(
-                apps::mojom::LaunchContainer::kLaunchContainerNone,
-                WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                true /* preferred_container */),
+            apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                true /* preferred_container */),
             apps::mojom::LaunchSource::kFromTest, std::move(launch_files));
     ASSERT_TRUE(catcher.GetNextResult());
   }
@@ -1331,10 +1329,8 @@
   registry->AddObserver(this);
   apps::AppServiceProxyFactory::GetForProfile(incognito_profile)
       ->Launch(file_manager->id(),
-               apps::GetEventFlags(
-                   apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                   WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                   true /* prefer_container */),
+               apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                   true /* prefer_container */),
                apps::mojom::LaunchSource::kFromTest);
 
   while (!base::Contains(opener_app_ids_, file_manager->id())) {
diff --git a/chrome/browser/ash/android_sms/android_sms_app_manager_impl.cc b/chrome/browser/ash/android_sms/android_sms_app_manager_impl.cc
index 7fa4fb1..eeb8c45 100644
--- a/chrome/browser/ash/android_sms/android_sms_app_manager_impl.cc
+++ b/chrome/browser/ash/android_sms/android_sms_app_manager_impl.cc
@@ -47,8 +47,7 @@
                                                     const std::string& app_id) {
   apps::AppServiceProxyFactory::GetForProfile(profile)->Launch(
       app_id,
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
                           false /* preferred_containner */),
       apps::mojom::LaunchSource::kFromChromeInternal);
 }
diff --git a/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
index 01a391f..af7b0bd6 100644
--- a/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
@@ -11,8 +11,9 @@
 #include "chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h"
 #include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 #include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
+#include "components/exo/client_controlled_shell_surface.h"
 #include "components/exo/surface.h"
-#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper_chromeos.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,18 +64,14 @@
  public:
   AccessibilityInfoDataWrapperTest() = default;
 
-  exo::test::ExoTestHelper exo_test_helper;
-
   std::unique_ptr<exo::WMHelper> wm_helper =
       std::make_unique<exo::WMHelperChromeOS>();
 };
 
 TEST_F(AccessibilityInfoDataWrapperTest, NonRootNodeBounds) {
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper root(&tree_source);
@@ -94,11 +91,9 @@
 TEST_F(AccessibilityInfoDataWrapperTest, RootNodeBounds) {
   UpdateDisplay("400x400");
 
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -114,11 +109,9 @@
 TEST_F(AccessibilityInfoDataWrapperTest, RootNodeBoundsOnExternalDisplay) {
   UpdateDisplay("400x400,500x500");
 
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(410, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(410, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -136,12 +129,10 @@
 
   // With default_scale_cancellation, Android has default (1x) scale factor.
   wm_helper->SetDefaultScaleCancellation(true);
-
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface = exo_test_helper.CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/true);
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 100, 100));  // DIP
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder()
+                           .SetGeometry(gfx::Rect(10, 10, 100, 100))
+                           .EnableDefaultScaleCancellation()
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -159,12 +150,9 @@
 
   // Without default_scale_cancellation, Android use the same (2x) scale factor.
   wm_helper->SetDefaultScaleCancellation(false);
-
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface = exo_test_helper.CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 100, 100));  // DIP
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
index f09467a2..6134c53 100644
--- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -29,7 +29,7 @@
 #include "components/exo/shell_surface.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
-#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper.h"
 #include "components/exo/wm_helper_chromeos.h"
 #include "components/viz/common/features.h"
@@ -47,12 +47,6 @@
 
 namespace {
 
-struct TestWindow {
-  std::unique_ptr<exo::Buffer> buffer;
-  std::unique_ptr<exo::Surface> surface;
-  std::unique_ptr<exo::ClientControlledShellSurface> shell_surface;
-};
-
 class MockAutomationEventRouter
     : public extensions::AutomationEventRouterInterface {
  public:
@@ -129,32 +123,15 @@
  protected:
   // Create and initialize a window for this test, i.e. an Arc++-specific
   // version of ExoTestHelper::CreateWindow.
-  TestWindow MakeTestArcWindow(std::string name) {
-    TestWindow ret = MakeNonArcTestWindow();
-
-    // Forcefully set task_id for each window.
-    ret.surface->SetApplicationId(name.c_str());
-
-    // CreateClientControlledShellSurface doesn't set AppType so do it here.
-    ret.shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
-        aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
-
-    return ret;
+  std::unique_ptr<exo::ClientControlledShellSurface> MakeTestArcWindow(
+      std::string name) {
+    return exo::test::ShellSurfaceBuilder({640, 480})
+        .SetApplicationId(name)
+        .BuildClientControlledShellSurface();
   }
 
-  TestWindow MakeNonArcTestWindow() {
-    TestWindow ret;
-    exo::test::ExoTestHelper helper;
-
-    ret.surface = std::make_unique<exo::Surface>();
-    ret.buffer = std::make_unique<exo::Buffer>(
-        helper.CreateGpuMemoryBuffer(gfx::Size(640, 480)));
-    ret.shell_surface = helper.CreateClientControlledShellSurface(
-        ret.surface.get(), /*is_modal=*/false);
-    ret.surface->Attach(ret.buffer.get());
-    ret.surface->Commit();
-
-    return ret;
+  std::unique_ptr<exo::ShellSurface> MakeNonArcTestWindow() {
+    return exo::test::ShellSurfaceBuilder({640, 480}).BuildShellSurface();
   }
 
   std::unique_ptr<FakeAccessibilityHelperInstance>
@@ -168,21 +145,19 @@
             fake_accessibility_helper_instance_->filter_type());
   EXPECT_FALSE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 
-  TestWindow test_window_1 = MakeTestArcWindow("org.chromium.arc.1");
-  TestWindow test_window_2 = MakeTestArcWindow("org.chromium.arc.2");
+  auto shell_surface1 = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface2 = MakeTestArcWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_1.shell_surface->GetWidget()->GetNativeWindow(),
+      shell_surface1->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(shell_surface1->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
-  ASSERT_FALSE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
-  ASSERT_FALSE(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  ASSERT_FALSE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
+  ASSERT_FALSE(shell_surface2->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
@@ -191,14 +166,13 @@
             fake_accessibility_helper_instance_->filter_type());
 
   // Use ChromeVox by default. Touch exploration pass through is still false.
-  EXPECT_FALSE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_FALSE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   ArcAccessibilityHelperBridge* bridge =
       ArcAccessibilityHelperBridge::GetForBrowserContext(browser()->profile());
 
-  // Enable TalkBack. Touch exploration pass through of test_window_1
+  // Enable TalkBack. Touch exploration pass through of shell_surface1
   // (current active window) would become true.
   bridge->SetNativeChromeVoxArcSupport(
       false,
@@ -206,36 +180,34 @@
           [](extensions::api::accessibility_private::SetNativeChromeVoxResponse
                  response) {}));
 
-  EXPECT_TRUE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_TRUE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
-  // Activate test_window_2 and confirm that it still be false.
+  // Activate shell_surface2 and confirm that it still be false.
   activation_client->ActivateWindow(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_2.shell_surface->GetWidget()->GetNativeWindow(),
+      shell_surface2->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(shell_surface2->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
-  EXPECT_FALSE(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_FALSE(shell_surface2->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   EXPECT_TRUE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 }
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest,
                        RequestTreeSyncOnWindowIdChange) {
-  TestWindow test_window_1 = MakeTestArcWindow("org.chromium.arc.1");
-  TestWindow test_window_2 = MakeTestArcWindow("org.chromium.arc.2");
+  auto shell_surface1 = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface2 = MakeTestArcWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
+      shell_surface1->GetWidget()->GetNativeWindow());
 
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
   exo::SetShellClientAccessibilityId(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow(), 10);
+      shell_surface1->GetWidget()->GetNativeWindow(), 10);
 
   EXPECT_TRUE(
       fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -245,14 +217,14 @@
                ->get_window_id());
 
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 20);
+      shell_surface2->GetWidget()->GetNativeWindow(), 20);
 
   EXPECT_EQ(
       20U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
                ->get_window_id());
 
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 21);
+      shell_surface2->GetWidget()->GetNativeWindow(), 21);
 
   EXPECT_EQ(
       21U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -280,11 +252,11 @@
                        FocusHighlight) {
   AccessibilityManager::Get()->SetFocusHighlightEnabled(true);
 
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      shell_surface->GetWidget()->GetNativeWindow());
 
   const gfx::Rect node_rect1 = gfx::Rect(50, 50, 50, 50);
 
@@ -345,7 +317,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest, PerformAction) {
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
   ArcAccessibilityHelperBridge* bridge =
@@ -385,7 +357,7 @@
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest,
                        GetTextLocation) {
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   AccessibilityManager::Get()->SetSelectToSpeakEnabled(true);
 
   ArcAccessibilityHelperBridge* bridge =
@@ -432,16 +404,16 @@
   base::HistogramTester histogram_tester;
 
   // Prepare ARC and non-ARC windows
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto arc_shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
 
-  TestWindow non_arc_window = MakeNonArcTestWindow();
+  auto non_arc_shell_surface = MakeNonArcTestWindow();
 
   // Turn on and off a feature while an ARC window is focused and then it will
   // be counted.
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 0);
   ash::MagnificationManager::Get()->SetMagnifierEnabled(true);
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 1);
@@ -456,23 +428,23 @@
   // Focus on an ARC window and focus on a non-ARC window while a feature is on
   // and then it will be counted.
   activation_client->ActivateWindow(
-      non_arc_window.shell_surface->GetWidget()->GetNativeWindow());
+      non_arc_shell_surface->GetWidget()->GetNativeWindow());
   ash::MagnificationManager::Get()->SetMagnifierEnabled(true);
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 2);
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 1);
   activation_client->ActivateWindow(
-      non_arc_window.shell_surface->GetWidget()->GetNativeWindow());
+      non_arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 2);
 
   // Close the focused ARC window while a feature is on and then it will be
   // counted.
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
-  test_window.surface.reset();
+      arc_shell_surface->GetWidget()->GetNativeWindow());
+  arc_shell_surface.reset();
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 3);
 
diff --git a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
index 134addf..a1ed859 100644
--- a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
+++ b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/arc/input_overlay/test/arc_test_window.h"
 #include "ash/constants/app_types.h"
 #include "ash/public/cpp/window_properties.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/display/screen.h"
 
@@ -15,22 +16,14 @@
 ArcTestWindow::ArcTestWindow(exo::test::ExoTestHelper* helper,
                              aura::Window* root,
                              const std::string& package_name) {
-  surface_ = std::make_unique<exo::Surface>();
-  buffer_ = std::make_unique<exo::Buffer>(
-      helper->CreateGpuMemoryBuffer(gfx::Size(100, 100)));
-  shell_surface_ =
-      helper->CreateClientControlledShellSurface(surface_.get(), false);
-  surface_->Attach(buffer_.get());
-
+  shell_surface_ = exo::test::ShellSurfaceBuilder({100, 100})
+                       .SetApplicationId(package_name.c_str())
+                       .BuildClientControlledShellSurface();
   auto display_id =
       display::Screen::GetScreen()->GetDisplayNearestWindow(root).id();
   shell_surface_->SetBounds(display_id, gfx::Rect(10, 10, 100, 100));
+  surface_ = shell_surface_->root_surface();
   surface_->Commit();
-  shell_surface_->GetWidget()->Show();
-  shell_surface_->GetWidget()->Activate();
-  surface_->SetApplicationId(package_name.c_str());
-  shell_surface_->GetWidget()->GetNativeWindow()->SetProperty(
-      aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
   shell_surface_->GetWidget()->GetNativeWindow()->SetProperty(
       ash::kArcPackageNameKey, package_name);
 }
diff --git a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
index 26afa72e..5f644ae 100644
--- a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
+++ b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
@@ -29,8 +29,7 @@
   void SetBounds(display::Display& display, gfx::Rect bounds);
 
  private:
-  std::unique_ptr<exo::Buffer> buffer_;
-  std::unique_ptr<exo::Surface> surface_;
+  exo::Surface* surface_;
   std::unique_ptr<exo::ClientControlledShellSurface> shell_surface_;
 };
 
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader.h b/chrome/browser/ash/attestation/enrollment_certificate_uploader.h
index 16e0d417..3d630ed 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader.h
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader.h
@@ -20,7 +20,10 @@
     // Cannot fetch enrollment certificate.
     kFailedToFetch,
     // Cannot upload fetched enrollment certificate.
-    kFailedToUpload
+    kFailedToUpload,
+    // Cannot fetch or upload enrollment certificate due to invalid
+    // `CloudPolicyClient`.
+    kInvalidClient
   };
 
   using UploadCallback = base::OnceCallback<void(Status status)>;
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
index b56bb81..4d9e095 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl.cc
@@ -80,13 +80,6 @@
 }
 
 void EnrollmentCertificateUploaderImpl::Start() {
-  // We expect a registered CloudPolicyClient.
-  if (!policy_client_->is_registered()) {
-    LOG(ERROR) << "CloudPolicyClient not registered.";
-    RunCallbacks(Status::kFailedToFetch);
-    return;
-  }
-
   if (!attestation_flow_) {
     std::unique_ptr<ServerProxy> attestation_ca_client(
         new AttestationCAClient());
@@ -99,6 +92,12 @@
 }
 
 void EnrollmentCertificateUploaderImpl::GetCertificate(bool force_new_key) {
+  if (!policy_client_->is_registered()) {
+    LOG(ERROR) << "CloudPolicyClient not registered.";
+    RunCallbacks(Status::kInvalidClient);
+    return;
+  }
+
   VLOG_IF(1, force_new_key) << "Fetching certificate with new key";
   attestation_flow_->GetCertificate(
       PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE,
@@ -180,6 +179,12 @@
     return;
   }
 
+  if (!policy_client_->is_registered()) {
+    LOG(ERROR) << "CloudPolicyClient not registered.";
+    RunCallbacks(Status::kInvalidClient);
+    return;
+  }
+
   policy_client_->UploadEnterpriseEnrollmentCertificate(
       pem_certificate_chain,
       base::BindOnce(&EnrollmentCertificateUploaderImpl::OnUploadComplete,
diff --git a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
index 347589c..7ed34a4 100644
--- a/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
+++ b/chrome/browser/ash/attestation/enrollment_certificate_uploader_impl_unittest.cc
@@ -107,7 +107,7 @@
       .Times(0);
 
   policy_client_.SetDMToken("");
-  Run(/*expected_status=*/CertStatus::kFailedToFetch);
+  Run(/*expected_status=*/CertStatus::kInvalidClient);
 }
 
 TEST_F(EnrollmentCertificateUploaderTest, GetCertificateUnspecifiedFailure) {
@@ -153,7 +153,7 @@
 
   EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)).Times(0);
 
-  Run(/*expected_status=*/CertStatus::kFailedToFetch);
+  Run(/*expected_status=*/CertStatus::kInvalidClient);
 }
 
 TEST_F(EnrollmentCertificateUploaderTest, UploadCertificateFailure) {
@@ -209,7 +209,51 @@
                              /*force_new_key=*/false, _, _))
       .Times(0);
 
-  Run(/*expected_status=*/CertStatus::kFailedToFetch);
+  Run(/*expected_status=*/CertStatus::kInvalidClient);
+}
+
+TEST_F(EnrollmentCertificateUploaderTest,
+       UnregisteredClientAfterValidCertificateRequested) {
+  std::string valid_certificate;
+  ASSERT_TRUE(GetFakeCertificatePEM(base::Days(1), &valid_certificate));
+  InSequence s;
+
+  // Shall fail on |CloudPolicyClient::is_registered()| check and not retry.
+  EXPECT_CALL(attestation_flow_,
+              GetCertificate(PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE, _, _,
+                             /*force_new_key=*/false, _, _))
+      .WillOnce(
+          WithArgs<5>(Invoke([this, valid_certificate](CertCallback callback) {
+            policy_client_.SetDMToken("");
+            CertCallbackSuccess(std::move(callback), valid_certificate);
+          })));
+
+  EXPECT_CALL(policy_client_, UploadEnterpriseEnrollmentCertificate(_, _))
+      .Times(0);
+
+  Run(/*expected_status=*/CertStatus::kInvalidClient);
+}
+
+TEST_F(EnrollmentCertificateUploaderTest,
+       UnregisteredClientAfterExpiredCertificateRequested) {
+  std::string expired_certificate;
+  ASSERT_TRUE(GetFakeCertificatePEM(base::Days(-1), &expired_certificate));
+  InSequence s;
+
+  // Shall fail on |CloudPolicyClient::is_registered()| check and not retry.
+  EXPECT_CALL(attestation_flow_,
+              GetCertificate(PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE, _, _,
+                             /*force_new_key=*/false, _, _))
+      .WillOnce(WithArgs<5>(
+          Invoke([this, expired_certificate](CertCallback callback) {
+            policy_client_.SetDMToken("");
+            CertCallbackSuccess(std::move(callback), expired_certificate);
+          })));
+
+  EXPECT_CALL(policy_client_, UploadEnterpriseEnrollmentCertificate(_, _))
+      .Times(0);
+
+  Run(/*expected_status=*/CertStatus::kInvalidClient);
 }
 
 TEST_F(EnrollmentCertificateUploaderTest, UploadValidCertificate) {
diff --git a/chrome/browser/ash/attestation/enrollment_id_upload_manager.cc b/chrome/browser/ash/attestation/enrollment_id_upload_manager.cc
index d61e69b0..2371052 100644
--- a/chrome/browser/ash/attestation/enrollment_id_upload_manager.cc
+++ b/chrome/browser/ash/attestation/enrollment_id_upload_manager.cc
@@ -120,6 +120,14 @@
       // later so we will not proceed with computed EID.
       RunCallbacks(/*status=*/false);
       break;
+    case EnrollmentCertificateUploader::Status::kInvalidClient:
+      // Enrollment certificate was not uploaded due to invalid
+      // `CloudPolicyClient`. The certificate can be uploaded later when the
+      // client is working again. The manager is also not able to upload EID
+      // with invalid `CloudPolicyClient` so there is no reason to fall back to
+      // EID computation.
+      RunCallbacks(/*status=*/false);
+      break;
   }
 }
 
diff --git a/chrome/browser/ash/attestation/enrollment_id_upload_manager_unittest.cc b/chrome/browser/ash/attestation/enrollment_id_upload_manager_unittest.cc
index bc423bf..9aa594ec 100644
--- a/chrome/browser/ash/attestation/enrollment_id_upload_manager_unittest.cc
+++ b/chrome/browser/ash/attestation/enrollment_id_upload_manager_unittest.cc
@@ -211,7 +211,7 @@
   policy_client_.SetDMToken("");
   SetUpDevicePolicy(/*enrollment_id_needed=*/true);
   SetUpEnrollmentIdUploadManager();
-  ExpectUploadEnrollmentCertificate(CertificateStatus::kFailedToFetch,
+  ExpectUploadEnrollmentCertificate(CertificateStatus::kInvalidClient,
                                     /*times=*/1);
   PropagateDevicePolicy();
   RunUntilIdle();
@@ -273,7 +273,7 @@
 TEST_F(EnrollmentIdUploadManagerTest, ObtainAndUploadUnregisteredPolicyClient) {
   policy_client_.SetDMToken("");
   SetUpEnrollmentIdUploadManager();
-  ExpectUploadEnrollmentCertificate(CertificateStatus::kFailedToFetch,
+  ExpectUploadEnrollmentCertificate(CertificateStatus::kInvalidClient,
                                     /*times=*/1);
   TestObtainAndUploadEnrollmentId(/*expect_success=*/false);
 }
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc
index 0a9731fd..8aa68bf 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.cc
@@ -76,6 +76,12 @@
 
 }  // namespace
 
+FailedWorkerInfo::FailedWorkerInfo() = default;
+FailedWorkerInfo::~FailedWorkerInfo() = default;
+FailedWorkerInfo::FailedWorkerInfo(const FailedWorkerInfo&) = default;
+FailedWorkerInfo& FailedWorkerInfo::operator=(const FailedWorkerInfo&) =
+    default;
+
 // static
 std::unique_ptr<CertProvisioningScheduler>
 CertProvisioningSchedulerImpl::CreateUserCertProvisioningScheduler(
@@ -679,6 +685,7 @@
   info.cert_profile_name = worker.GetCertProfile().name;
   info.public_key = worker.GetPublicKey();
   info.last_update_time = worker.GetLastUpdateTime();
+  info.failure_message = worker.GetFailureMessage();
 
   failed_cert_profiles_[worker.GetCertProfile().profile_id] = std::move(info);
 }
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h
index 30fb15f..c8eae0a 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler.h
@@ -46,6 +46,10 @@
 // Holds information about a worker which failed that is still useful (e.g. for
 // UI) after the worker has been destroyed.
 struct FailedWorkerInfo {
+  FailedWorkerInfo();
+  ~FailedWorkerInfo();
+  FailedWorkerInfo(const FailedWorkerInfo&);
+  FailedWorkerInfo& operator=(const FailedWorkerInfo&);
   // The state the worker had prior to switching to the failed state
   // (CertProvisioningWorkerState::kFailed).
   CertProvisioningWorkerState state_before_failure =
@@ -57,6 +61,8 @@
   // The time the worker was last updated, i.e. when it transferred to the
   // failed state.
   base::Time last_update_time;
+  // Holds a message describing the reason for the failure.
+  std::string failure_message;
 };
 
 // Interface for the scheduler for client certificate provisioning using device
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_unittest.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_unittest.cc
index 1884a2f..0946d586 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_unittest.cc
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_scheduler_unittest.cc
@@ -231,7 +231,8 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
-                          /*is_waiting=*/false, cert_profile);
+                          /*is_waiting=*/false, cert_profile,
+                          /*failure_message=*/"");
 
   // Add 1 certificate profile to the policy (the values are the same as
   // in |cert_profile|).
@@ -285,7 +286,8 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
-                          /*is_waiting=*/false, cert_profile);
+                          /*is_waiting=*/false, cert_profile,
+                          /*failure_message=*/"reason for failure");
 
   // Add 1 certificate profile to the policy (the values are the same as
   // in |cert_profile|).
@@ -303,6 +305,13 @@
   scheduler.OnProfileFinished(cert_profile,
                               CertProvisioningWorkerState::kFailed);
 
+  // The failure message in the FailedWorkerInfo object should match the
+  // failure message passed to the mock worker
+  EXPECT_EQ(scheduler.GetFailedCertProfileIds().size(), 1U);
+  EXPECT_EQ(
+      scheduler.GetFailedCertProfileIds().at(kCertProfileId).failure_message,
+      "reason for failure");
+
   // Failed worker should be deleted, failed profile ID is saved, no new
   // workers should be created.
   EXPECT_EQ(scheduler.GetWorkers().size(), 0U);
@@ -342,7 +351,7 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile);
+                          cert_profile, /*failure_message=*/"");
   FastForwardBy(base::Seconds(1));
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
@@ -366,7 +375,7 @@
   MockCertProvisioningWorker* worker2 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker2->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile);
+                           cert_profile, /*failure_message=*/"");
   FastForwardBy(base::Hours(5));
   ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
@@ -416,15 +425,15 @@
   MockCertProvisioningWorker* worker0 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile0);
   worker0->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile0);
+                           cert_profile0, /*failure_message=*/"");
   MockCertProvisioningWorker* worker1 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile1);
   worker1->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile1);
+                           cert_profile1, /*failure_message=*/"");
   MockCertProvisioningWorker* worker2 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile2);
   worker2->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile2);
+                           cert_profile2, /*failure_message=*/"");
 
   // Add 3 certificate profiles to the policy (the values are the same as
   // in |cert_profile|-s)
@@ -458,7 +467,7 @@
 
   // worker1 is waiting. Should be continued.
   worker1->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/true,
-                           cert_profile1);
+                           cert_profile1, /*failure_message=*/"");
 
   // worker2 failed. Should be deleted and the profile id should be saved.
   scheduler.OnProfileFinished(cert_profile2,
@@ -541,7 +550,8 @@
   // is_waiting==true should be set by Serializer so Scheduler knows that the
   // worker has to be continued manually.
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
-                          /*is_waiting=*/true, cert_profile);
+                          /*is_waiting=*/true, cert_profile,
+                          /*failure_message=*/"");
 
   CertProvisioningSchedulerImpl scheduler(
       kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
@@ -580,7 +590,7 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v1);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile_v1);
+                          cert_profile_v1, /*failure_message=*/"");
 
   // Add 1 certificate profile to the policy (the values are the same as
   // in |cert_profile_v1|).
@@ -606,7 +616,7 @@
   // Add a new worker to the factory.
   worker = mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v1);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile_v1);
+                          cert_profile_v1, /*failure_message=*/"");
 
   // After some delay a new worker should be created to try again.
   FastForwardBy(base::Seconds(31));
@@ -627,7 +637,7 @@
       /*is_va_enabled=*/true, kCertProfileRenewalPeriod);
   worker = mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile_v2);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile_v2);
+                          cert_profile_v2, /*failure_message=*/"");
 
   // On policy update a new worker should be created to try again.
   config = ParseJson(
@@ -697,7 +707,7 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile);
+                          cert_profile, /*failure_message=*/"");
 
   SetWifiNetworkState(shill::kStateOnline);
 
@@ -728,7 +738,7 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile);
+                          cert_profile, /*failure_message=*/"");
 
   // Prefs update will be ignored because initialization task has not finished
   // yet.
@@ -803,7 +813,8 @@
     // This worker should be deleted approximately right after creation, hence
     // no calls for DoStep.
     worker->SetExpectations(/*do_step_times=*/Exactly(0),
-                            /*is_waiting=*/true, cert_profile);
+                            /*is_waiting=*/true, cert_profile,
+                            /*failure_message=*/"");
 
     CertProvisioningSchedulerImpl scheduler(
         kCertScope, GetProfile(), &pref_service_, &cloud_policy_client_,
@@ -843,7 +854,8 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/Exactly(1),
-                          /*is_waiting=*/false, cert_profile);
+                          /*is_waiting=*/false, cert_profile,
+                          /*failure_message=*/"");
 
   // Add 1 certificate profile to the policy (the values are the same as
   // in |cert_profile|).
@@ -858,7 +870,8 @@
   // If worker is waiting, it should be continued.
   {
     worker->SetExpectations(/*do_step_times=*/Exactly(1),
-                            /*is_waiting=*/true, cert_profile);
+                            /*is_waiting=*/true, cert_profile,
+                            /*failure_message=*/"");
 
     scheduler.UpdateOneWorker(kCertProfileId);
     FastForwardBy(base::Seconds(1));
@@ -868,7 +881,8 @@
   // If worker is not waiting, it should not be continued.
   {
     worker->SetExpectations(/*do_step_times=*/Exactly(0),
-                            /*is_waiting=*/false, cert_profile);
+                            /*is_waiting=*/false, cert_profile,
+                            /*failure_message=*/"");
 
     scheduler.UpdateOneWorker(kCertProfileId);
     FastForwardBy(base::Seconds(1));
@@ -881,14 +895,16 @@
     SetWifiNetworkState(shill::kStateIdle);
 
     worker->SetExpectations(/*do_step_times=*/Exactly(0),
-                            /*is_waiting=*/true, cert_profile);
+                            /*is_waiting=*/true, cert_profile,
+                            /*failure_message=*/"");
 
     scheduler.UpdateOneWorker(kCertProfileId);
     FastForwardBy(base::Seconds(1));
     ASSERT_EQ(scheduler.GetWorkers().size(), 1U);
 
     worker->SetExpectations(/*do_step_times=*/Exactly(1),
-                            /*is_waiting=*/true, cert_profile);
+                            /*is_waiting=*/true, cert_profile,
+                            /*failure_message=*/"");
 
     SetWifiNetworkState(shill::kStateOnline);
   }
@@ -955,7 +971,8 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1),
-                          /*is_waiting=*/false, cert_profile);
+                          /*is_waiting=*/false, cert_profile,
+                          /*failure_message=*/"");
 
   // One day (according to the policy) before the certificate expires, scheduler
   // should create a new worker to provision a replacement.
@@ -995,7 +1012,7 @@
   MockCertProvisioningWorker* worker =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile);
   worker->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                          cert_profile);
+                          cert_profile, /*failure_message=*/"");
   scheduler.UpdateAllWorkers();
 
   // Now 1 worker should be created.
@@ -1051,11 +1068,11 @@
   MockCertProvisioningWorker* worker0 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile0);
   worker0->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile0);
+                           cert_profile0, /*failure_message=*/"");
   MockCertProvisioningWorker* worker1 =
       mock_factory_.ExpectCreateReturnMock(kCertScope, cert_profile1);
   worker1->SetExpectations(/*do_step_times=*/AtLeast(1), /*is_waiting=*/false,
-                           cert_profile1);
+                           cert_profile1, /*failure_message=*/"");
 
   // Add 2 certificate profiles to the policy (the values are the same as
   // in |cert_profile|-s)
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.cc b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.cc
index b12f081a..08b54f04 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.cc
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.cc
@@ -8,6 +8,8 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/no_destructor.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/syslog_logging.h"
 #include "base/time/time.h"
 #include "chrome/browser/ash/attestation/tpm_challenge_key_result.h"
@@ -161,6 +163,20 @@
   }
 }
 
+// The original message of kUserNotManagedError is misleading in case the user
+// is not affiliated. In this case, the error message associated to the error
+// code kUserNotManagedError is replaced.
+std::string ConstructFailureMessage(
+    const attestation::TpmChallengeKeyResult& challenge_result) {
+  std::string failure_message = "Failed to build challenge response: ";
+  if (challenge_result.result_code ==
+      attestation::TpmChallengeKeyResultCode::kUserNotManagedError) {
+    return (failure_message +
+            "User is not affiliated. Certificate profile is not applicable.");
+  }
+  return (failure_message + challenge_result.GetErrorMessage());
+}
+
 }  // namespace
 
 // ============= CertProvisioningWorkerFactory =================================
@@ -295,13 +311,17 @@
   return last_backend_server_error_;
 }
 
+const std::string& CertProvisioningWorkerImpl::GetFailureMessage() const {
+  return failure_message_;
+}
+
 void CertProvisioningWorkerImpl::Stop(CertProvisioningWorkerState state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   DCHECK(IsFinalState(state));
 
   CancelScheduledTasks();
-  UpdateState(state);
+  UpdateState(FROM_HERE, state);
 }
 
 void CertProvisioningWorkerImpl::Pause() {
@@ -352,6 +372,7 @@
 }
 
 void CertProvisioningWorkerImpl::UpdateState(
+    const base::Location& from_here,
     CertProvisioningWorkerState new_state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -370,6 +391,11 @@
 
   HandleSerialization();
 
+  if (state_ == CertProvisioningWorkerState::kFailed) {
+    LOG(ERROR) << "Failure state from " << from_here.ToString()
+               << ". Details: " << failure_message_;
+  }
+
   state_change_callback_.Run();
   if (IsFinalState(state_)) {
     CleanUpAndRunCallback();
@@ -397,14 +423,15 @@
     chromeos::platform_keys::Status status) {
   if (status != chromeos::platform_keys::Status::kSuccess ||
       public_key_spki_der.empty()) {
-    LOG(ERROR) << "Failed to prepare a non-VA key: "
-               << chromeos::platform_keys::StatusToString(status);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        base::StrCat({"Failed to prepare a non-VA key: ",
+                      chromeos::platform_keys::StatusToString(status)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   public_key_ = public_key_spki_der;
-  UpdateState(CertProvisioningWorkerState::kKeypairGenerated);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kKeypairGenerated);
   DoStep();
 }
 
@@ -439,13 +466,14 @@
   }
 
   if (!result.IsSuccess() || result.public_key.empty()) {
-    LOG(ERROR) << "Failed to prepare a key: " << result.GetErrorMessage();
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        std::string("Failed to prepare a key: ") + result.GetErrorMessage();
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   public_key_ = result.public_key;
-  UpdateState(CertProvisioningWorkerState::kKeypairGenerated);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kKeypairGenerated);
   DoStep();
 }
 
@@ -475,21 +503,22 @@
   }
 
   if (!ConvertHashingAlgorithm(hashing_algorithm, &hashing_algorithm_)) {
-    LOG(ERROR) << "Failed to parse hashing algorithm";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = "Failed to parse hashing algorithm";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   if (cert_profile_.is_va_enabled && va_challenge.empty()) {
-    LOG(ERROR) << "VA challenge is required, but not included";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = "VA challenge is required, but not included";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   csr_ = data_to_sign;
   invalidation_topic_ = invalidation_topic;
   va_challenge_ = va_challenge;
-  UpdateState(CertProvisioningWorkerState::kStartCsrResponseReceived);
+  UpdateState(FROM_HERE,
+              CertProvisioningWorkerState::kStartCsrResponseReceived);
 
   RegisterForInvalidationTopic();
 
@@ -498,7 +527,7 @@
 
 void CertProvisioningWorkerImpl::ProcessStartCsrResponse() {
   if (!cert_profile_.is_va_enabled) {
-    UpdateState(CertProvisioningWorkerState::kKeyRegistered);
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kKeyRegistered);
     DoStep();
     return;
   }
@@ -518,26 +547,25 @@
 
 void CertProvisioningWorkerImpl::OnBuildVaChallengeResponseDone(
     base::TimeTicks start_time,
-    const attestation::TpmChallengeKeyResult& result) {
+    const attestation::TpmChallengeKeyResult& challenge_result) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   RecordVerifiedAccessTime(cert_scope_, base::TimeTicks::Now() - start_time);
 
-  if (!result.IsSuccess()) {
-    LOG(ERROR) << "Failed to build challenge response: "
-               << result.GetErrorMessage();
-    UpdateState(CertProvisioningWorkerState::kFailed);
+  if (!challenge_result.IsSuccess()) {
+    failure_message_ = ConstructFailureMessage(challenge_result);
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
-  if (result.challenge_response.empty()) {
-    LOG(ERROR) << "Challenge response is empty";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+  if (challenge_result.challenge_response.empty()) {
+    failure_message_ = "Challenge response is empty";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
-  va_challenge_response_ = result.challenge_response;
-  UpdateState(CertProvisioningWorkerState::kVaChallengeFinished);
+  va_challenge_response_ = challenge_result.challenge_response;
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kVaChallengeFinished);
   DoStep();
 }
 
@@ -556,12 +584,13 @@
   tpm_challenge_key_subtle_impl_.reset();
 
   if (!result.IsSuccess()) {
-    LOG(ERROR) << "Failed to register key: " << result.GetErrorMessage();
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        base::StrCat({"Failed to register key: ", result.GetErrorMessage()});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
-  UpdateState(CertProvisioningWorkerState::kKeyRegistered);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kKeyRegistered);
   DoStep();
 }
 
@@ -583,13 +612,14 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (status != chromeos::platform_keys::Status::kSuccess) {
-    LOG(ERROR) << "Failed to mark a key: "
-               << chromeos::platform_keys::StatusToString(status);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        base::StrCat({"Failed to mark a key: ",
+                      chromeos::platform_keys::StatusToString(status)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
-  UpdateState(CertProvisioningWorkerState::kKeypairMarked);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kKeypairMarked);
   DoStep();
 }
 
@@ -597,8 +627,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (!hashing_algorithm_.has_value()) {
-    LOG(ERROR) << "Hashing algorithm is empty";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = "Hashing algorithm is empty";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
@@ -627,14 +657,15 @@
   RecordCsrSignTime(cert_scope_, base::TimeTicks::Now() - start_time);
 
   if (status != chromeos::platform_keys::Status::kSuccess) {
-    LOG(ERROR) << "Failed to sign CSR: "
-               << chromeos::platform_keys::StatusToString(status);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        base::StrCat({"Failed to sign CSR: ",
+                      chromeos::platform_keys::StatusToString(status)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   signature_ = signature;
-  UpdateState(CertProvisioningWorkerState::kSignCsrFinished);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kSignCsrFinished);
   DoStep();
 }
 
@@ -660,7 +691,8 @@
     return;
   }
 
-  UpdateState(CertProvisioningWorkerState::kFinishCsrResponseReceived);
+  UpdateState(FROM_HERE,
+              CertProvisioningWorkerState::kFinishCsrResponseReceived);
   DoStep();
 }
 
@@ -696,16 +728,17 @@
   scoped_refptr<net::X509Certificate> cert = CreateSingleCertificateFromBytes(
       pem_encoded_certificate.data(), pem_encoded_certificate.size());
   if (!cert) {
-    LOG(ERROR) << "Failed to parse a certificate";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = "Failed to parse a certificate";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
   std::string public_key_from_cert =
       chromeos::platform_keys::GetSubjectPublicKeyInfo(cert);
   if (public_key_from_cert != public_key_) {
-    LOG(ERROR) << "Downloaded certificate does not match the expected key pair";
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        "Downloaded certificate does not match the expected key pair";
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
@@ -720,13 +753,14 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (status != chromeos::platform_keys::Status::kSuccess) {
-    LOG(ERROR) << "Failed to import certificate: "
-               << chromeos::platform_keys::StatusToString(status);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ =
+        base::StrCat({"Failed to import certificate: ",
+                      chromeos::platform_keys::StatusToString(status)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return;
   }
 
-  UpdateState(CertProvisioningWorkerState::kSucceeded);
+  UpdateState(FROM_HERE, CertProvisioningWorkerState::kSucceeded);
 }
 
 bool CertProvisioningWorkerImpl::ProcessResponseErrors(
@@ -766,11 +800,11 @@
   }
 
   if (status != policy::DeviceManagementStatus::DM_STATUS_SUCCESS) {
-    LOG(ERROR) << "DM Server returned error: " << status
-               << " for profile ID: " << cert_profile_.profile_id
-               << " in state: "
-               << CertificateProvisioningWorkerStateToString(state_);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = base::StrCat(
+        {"DM Server returned error: ", base::NumberToString(status),
+         " for profile ID: ", cert_profile_.profile_id,
+         " in state: ", CertificateProvisioningWorkerStateToString(state_)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return false;
   }
 
@@ -782,16 +816,17 @@
                << " for profile ID: " << cert_profile_.profile_id
                << " in state: "
                << CertificateProvisioningWorkerStateToString(state_);
-    UpdateState(CertProvisioningWorkerState::kInconsistentDataError);
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kInconsistentDataError);
     return false;
   }
 
   if (error.has_value()) {
-    LOG(ERROR) << "Server response contains error: " << error.value()
-               << " for profile ID: " << cert_profile_.profile_id
-               << " in state: "
-               << CertificateProvisioningWorkerStateToString(state_);
-    UpdateState(CertProvisioningWorkerState::kFailed);
+    failure_message_ = base::StrCat(
+        {"Server response contains error: ",
+         base::NumberToString(error.value()),
+         " for profile ID: ", cert_profile_.profile_id,
+         " in state: ", CertificateProvisioningWorkerStateToString(state_)});
+    UpdateState(FROM_HERE, CertProvisioningWorkerState::kFailed);
     return false;
   }
 
diff --git a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.h b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.h
index 6d65206..2f021d3 100644
--- a/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.h
+++ b/chrome/browser/ash/cert_provisioning/cert_provisioning_worker.h
@@ -115,6 +115,9 @@
   // Return the info of when this worker has last faced an unsuccessful attempt.
   virtual const absl::optional<BackendServerError>& GetLastBackendServerError()
       const = 0;
+  // Return a message describing the reason for failure when the worker fails.
+  // In case the worker did not fail, the message is empty.
+  virtual const std::string& GetFailureMessage() const = 0;
 };
 
 class CertProvisioningWorkerImpl : public CertProvisioningWorker {
@@ -142,6 +145,7 @@
   base::Time GetLastUpdateTime() const override;
   const absl::optional<BackendServerError>& GetLastBackendServerError()
       const override;
+  const std::string& GetFailureMessage() const override;
 
  private:
   friend class CertProvisioningSerializer;
@@ -215,7 +219,8 @@
   // If it is called with kSucceed or kFailed, it will call the |callback_|. The
   // worker can be destroyed in callback and should not use any member fields
   // after that.
-  void UpdateState(CertProvisioningWorkerState state);
+  void UpdateState(const base::Location& from_here,
+                   CertProvisioningWorkerState state);
 
   // Serializes the worker or deletes serialized state accroding to the current
   // state. Some states are considered unrecoverable, some can be reached again
@@ -284,6 +289,10 @@
   absl::optional<chromeos::platform_keys::HashAlgorithm> hashing_algorithm_;
   std::string signature_;
 
+  // Holds a message describing the reason for failure when the worker fails.
+  // If the worker did not fail, this message is empty.
+  std::string failure_message_;
+
   // IMPORTANT:
   // Increment this when you add/change any member in CertProvisioningWorkerImpl
   // that affects serialization (and update all functions that fail to compile
diff --git a/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.cc b/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.cc
index 288968f..817fa593 100644
--- a/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.cc
+++ b/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.cc
@@ -65,14 +65,18 @@
 void MockCertProvisioningWorker::SetExpectations(
     testing::Cardinality do_step_times,
     bool is_waiting,
-    const CertProfile& cert_profile) {
+    const CertProfile& cert_profile,
+    std::string failure_message) {
   testing::Mock::VerifyAndClearExpectations(this);
 
   cert_profile_ = cert_profile;
+  failure_message_ = std::move(failure_message);
 
   EXPECT_CALL(*this, DoStep).Times(do_step_times);
   EXPECT_CALL(*this, IsWaiting).WillRepeatedly(Return(is_waiting));
   EXPECT_CALL(*this, GetCertProfile).WillRepeatedly(ReturnRef(cert_profile_));
+  EXPECT_CALL(*this, GetFailureMessage)
+      .WillRepeatedly(ReturnRef(failure_message_));
 }
 
 }  // namespace cert_provisioning
diff --git a/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.h b/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.h
index fc33298d..ba6a8e6 100644
--- a/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.h
+++ b/chrome/browser/ash/cert_provisioning/mock_cert_provisioning_worker.h
@@ -82,15 +82,18 @@
               (),
               (const override));
   MOCK_METHOD(base::Time, GetLastUpdateTime, (), (const override));
+  MOCK_METHOD(const std::string&, GetFailureMessage, (), (const override));
 
   void SetExpectations(testing::Cardinality do_step_times,
                        bool is_waiting,
-                       const CertProfile& cert_profile);
+                       const CertProfile& cert_profile,
+                       std::string failure_message);
 
-  // Stores |cert_profile| for SetExpectations function. It is returned by
-  // reference and without copying it there is a risk that the original
-  // CertProfile can be deleted before clearing the expectation.
+  // Storage fields for SetExpectations function. They are returned by
+  // reference and without copying them there is a risk that the original
+  // objects can be deleted before clearing the expectation.
   CertProfile cert_profile_;
+  std::string failure_message_;
 };
 
 }  // namespace cert_provisioning
diff --git a/chrome/browser/ash/crosapi/browser_data_migrator.cc b/chrome/browser/ash/crosapi/browser_data_migrator.cc
index 6d6da67..8069753 100644
--- a/chrome/browser/ash/crosapi/browser_data_migrator.cc
+++ b/chrome/browser/ash/crosapi/browser_data_migrator.cc
@@ -82,10 +82,10 @@
     const AccountId& account_id,
     const std::string& user_id_hash,
     crosapi::browser_util::PolicyInitState policy_init_state) {
-  LOG(WARNING) << "MaybeForceResumeMoveMigration() is called.";
   if (!MoveMigrator::ResumeRequired(local_state, user_id_hash))
     return false;
 
+  LOG(WARNING) << "Calling RestartToMigrate() to resume move migration.";
   return RestartToMigrate(account_id, user_id_hash, local_state,
                           policy_init_state);
 }
@@ -166,10 +166,6 @@
     const AccountId& account_id,
     const std::string& user_id_hash,
     crosapi::browser_util::PolicyInitState policy_init_state) {
-  // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove this
-  // log message.
-  LOG(WARNING) << "MaybeRestartToMigrateInternal() is called.";
-
   auto* user_manager = user_manager::UserManager::Get();
   auto* local_state = user_manager->GetLocalState();
 
@@ -287,7 +283,7 @@
   int attempts = GetMigrationAttemptCountForUser(local_state, user_id_hash);
   // TODO(crbug.com/1178702): Once BrowserDataMigrator stabilises, reduce the
   // log level to VLOG(1).
-  LOG(WARNING) << "Attempt #" << attempts;
+  LOG_IF(WARNING, attempts > 0) << "Attempt #" << attempts;
   if (attempts >= kMaxMigrationAttemptCount) {
     // TODO(crbug.com/1277848): Once `BrowserDataMigrator` stabilises, remove
     // this log message.
diff --git a/chrome/browser/ash/crosapi/cert_provisioning_ash.cc b/chrome/browser/ash/crosapi/cert_provisioning_ash.cc
index dda169f..fdcb994 100644
--- a/chrome/browser/ash/crosapi/cert_provisioning_ash.cc
+++ b/chrome/browser/ash/crosapi/cert_provisioning_ash.cc
@@ -177,6 +177,7 @@
     status->state = AshToMojoState(worker.state_before_failure);
     status->did_fail = true;
     status->is_device_wide = is_device_wide;
+    status->failure_message = worker.failure_message;
   }
 }
 
diff --git a/chrome/browser/ash/crosapi/cert_provisioning_ash_unittest.cc b/chrome/browser/ash/crosapi/cert_provisioning_ash_unittest.cc
index 41a3122..961171db 100644
--- a/chrome/browser/ash/crosapi/cert_provisioning_ash_unittest.cc
+++ b/chrome/browser/ash/crosapi/cert_provisioning_ash_unittest.cc
@@ -26,6 +26,10 @@
 namespace crosapi {
 namespace {
 
+// Fake failure message used for tests. The exact content of the message can be
+// chosen arbitrarily.
+const char kFakeFailureMessage[] = "Failure Message";
+
 // Extracted from a X.509 certificate using the command:
 // openssl x509 -pubkey -noout -in cert.pem
 // and reformatted as a single line.
@@ -276,6 +280,7 @@
       mojom::CertProvisioningProcessState::kKeypairGenerated;
   expected_user_status->did_fail = false;
   expected_user_status->is_device_wide = false;
+  expected_user_status->failure_message = absl::nullopt;
 
   TestFuture<std::vector<mojom::CertProvisioningProcessStatusPtr>> result;
   service_.GetStatus(result.GetCallback());
@@ -316,6 +321,7 @@
       mojom::CertProvisioningProcessState::kSignCsrFinished;
   expected_device_status->did_fail = false;
   expected_device_status->is_device_wide = true;
+  expected_device_status->failure_message = absl::nullopt;
 
   TestFuture<std::vector<mojom::CertProvisioningProcessStatusPtr>> result;
   service_.GetStatus(result.GetCallback());
@@ -336,6 +342,7 @@
   info.public_key = der_encoded_spki_str_;
   info.cert_profile_name = kFailedUserCertProfileName;
   info.last_update_time = last_update_time;
+  info.failure_message = kFakeFailureMessage;
 
   auto expected_user_status = mojom::CertProvisioningProcessStatus::New();
   expected_user_status->cert_profile_id = kFailedUserCertProfileId;
@@ -346,6 +353,7 @@
       mojom::CertProvisioningProcessState::kVaChallengeFinished;
   expected_user_status->did_fail = true;
   expected_user_status->is_device_wide = false;
+  expected_user_status->failure_message = kFakeFailureMessage;
 
   TestFuture<std::vector<mojom::CertProvisioningProcessStatusPtr>> result;
   service_.GetStatus(result.GetCallback());
@@ -366,6 +374,7 @@
   info.public_key = der_encoded_spki_str_;
   info.cert_profile_name = kFailedDeviceCertProfileName;
   info.last_update_time = last_update_time;
+  info.failure_message = kFakeFailureMessage;
 
   auto expected_device_status = mojom::CertProvisioningProcessStatus::New();
   expected_device_status->cert_profile_id = kFailedDeviceCertProfileId;
@@ -376,6 +385,7 @@
       mojom::CertProvisioningProcessState::kFinishCsrResponseReceived;
   expected_device_status->did_fail = true;
   expected_device_status->is_device_wide = true;
+  expected_device_status->failure_message = kFakeFailureMessage;
 
   TestFuture<std::vector<mojom::CertProvisioningProcessStatusPtr>> result;
   service_.GetStatus(result.GetCallback());
diff --git a/chrome/browser/ash/crosapi/device_settings_ash.cc b/chrome/browser/ash/crosapi/device_settings_ash.cc
index cadd1bb..e2c361a 100644
--- a/chrome/browser/ash/crosapi/device_settings_ash.cc
+++ b/chrome/browser/ash/crosapi/device_settings_ash.cc
@@ -12,8 +12,8 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/policy/chrome_policy_conversions_client.h"
+#include "chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
 namespace crosapi {
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest.cc b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
index 5dc03091..63e3ca18 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest.cc
@@ -166,6 +166,11 @@
     return *this;
   }
 
+  TestCase& EnableMirrorSync() {
+    options.enable_mirrorsync = true;
+    return *this;
+  }
+
   std::string GetFullName() const {
     std::string full_name = name;
 
@@ -208,6 +213,9 @@
     if (options.enable_filters_in_recents_v2)
       full_name += "_FiltersInRecentsV2";
 
+    if (options.enable_mirrorsync)
+      full_name += "_MirrorSync";
+
     return full_name;
   }
 
@@ -1620,7 +1628,11 @@
         TestCase("openHelpPageFromDownloadsVolume"),
         TestCase("openHelpPageFromDownloadsVolume").FilesSwa(),
         TestCase("openHelpPageFromDriveVolume"),
-        TestCase("openHelpPageFromDriveVolume").FilesSwa()));
+        TestCase("openHelpPageFromDriveVolume").FilesSwa(),
+        TestCase("showManageMirrorSyncShowsOnlyInLocalRoot").FilesSwa(),
+        TestCase("showManageMirrorSyncShowsOnlyInLocalRoot")
+            .EnableMirrorSync()
+            .FilesSwa()));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
     FilesTooltip, /* files_tooltip.js */
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 0990b051..cc0a5ca 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.cc
@@ -1935,6 +1935,12 @@
     disabled_features.push_back(chromeos::features::kFilesWebDriveOffice);
   }
 
+  if (options.enable_mirrorsync) {
+    enabled_features.push_back(chromeos::features::kDriveFsMirroring);
+  } else {
+    disabled_features.push_back(chromeos::features::kDriveFsMirroring);
+  }
+
   if (command_line->HasSwitch(switches::kDevtoolsCodeCoverage) &&
       options.guest_mode != IN_INCOGNITO) {
     devtools_code_coverage_dir_ =
@@ -3060,6 +3066,11 @@
     return;
   }
 
+  if (name == "isMirrorSyncEnabled") {
+    *output = options.enable_mirrorsync ? "true" : "false";
+    return;
+  }
+
   if (name == "switchLanguage") {
     const std::string* language = value.FindStringKey("language");
     ASSERT_TRUE(language);
diff --git a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
index aee3f6bf..7fe3f1d 100644
--- a/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/ash/file_manager/file_manager_browsertest_base.h
@@ -135,6 +135,9 @@
 
     // Whether test needs the files-filters-in-recents-v2 flag.
     bool enable_filters_in_recents_v2 = false;
+
+    // Whether test should run with the DriveFsMirroring flag.
+    bool enable_mirrorsync = false;
   };
 
   FileManagerBrowserTestBase(const FileManagerBrowserTestBase&) = delete;
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 3deae22..2272dc4 100644
--- a/chrome/browser/ash/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/ash/file_manager/file_manager_string_util.cc
@@ -170,6 +170,8 @@
   SET_STRING("SYNC_NO_SERVER_SPACE", IDS_FILE_BROWSER_SYNC_NO_SERVER_SPACE);
   SET_STRING("SYNC_SERVICE_UNAVAILABLE_ERROR",
              IDS_FILE_BROWSER_SYNC_SERVICE_UNAVAILABLE_ERROR);
+  SET_STRING("DRIVE_MANAGE_MIRRORSYNC",
+             IDS_FILE_BROWSER_DRIVE_MANAGE_MIRRORSYNC_LABEL);
 }
 
 void AddStringsForMediaView(base::Value::Dict* dict) {
@@ -1028,6 +1030,9 @@
   dict->Set("FUSEBOX_DEBUG",
             base::FeatureList::IsEnabled(chromeos::features::kFuseBoxDebug));
 
+  dict->Set("DRIVEFS_MIRRORING",
+            chromeos::features::IsDriveFsMirroringEnabled());
+
   dict->Set("GUEST_OS",
             base::FeatureList::IsEnabled(chromeos::features::kGuestOsFiles));
 
diff --git a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
index 769df8b..6e941c5 100644
--- a/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
+++ b/chrome/browser/ash/policy/core/device_local_account_browsertest.cc
@@ -1552,14 +1552,12 @@
   run_loop_ = std::make_unique<base::RunLoop>();
   auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
   proxy->FlushMojoCallsForTesting();
-  proxy->Launch(
-      app->id(),
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* preferred_containner */),
-      apps::mojom::LaunchSource::kFromChromeInternal,
-      apps::MakeWindowInfo(
-          display::Screen::GetScreen()->GetPrimaryDisplay().id()));
+  proxy->Launch(app->id(),
+                apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                    false /* preferred_containner */),
+                apps::mojom::LaunchSource::kFromChromeInternal,
+                apps::MakeWindowInfo(
+                    display::Screen::GetScreen()->GetPrimaryDisplay().id()));
   proxy->FlushMojoCallsForTesting();
   run_loop_->Run();
   EXPECT_EQ(1U, app_window_registry->app_windows().size());
diff --git a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
index 55f2b8e..4736415f 100644
--- a/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
+++ b/chrome/browser/browsing_data/counters/passwords_counter_browsertest.cc
@@ -135,8 +135,10 @@
     PasswordForm result;
     result.signon_realm = origin;
     result.url = GURL(origin);
-    result.username_value = base::ASCIIToUTF16(username);
-    result.password_value = u"hunter2";
+    if (!blocked_by_user) {
+      result.username_value = base::ASCIIToUTF16(username);
+      result.password_value = u"hunter2";
+    }
     result.blocked_by_user = blocked_by_user;
     result.date_created = time_;
     result.times_used = times_used_;
@@ -183,8 +185,8 @@
 // Tests that the counter doesn't count blocklisted entries.
 IN_PROC_BROWSER_TEST_F(PasswordsCounterTest, blocklisted) {
   AddLogin("https://www.google.com", "user1", false);
-  AddLogin("https://www.google.com", "user2", true);
-  AddLogin("https://www.chrome.com", "user3", true);
+  AddLogin("https://www.google.com", "", true);
+  AddLogin("https://www.chrome.com", "", true);
 
   Profile* profile = browser()->profile();
   browsing_data::PasswordsCounter counter(
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 8422a654..b20c0493 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -15,6 +15,8 @@
 #include "ash/components/arc/arc_prefs.h"
 #include "ash/components/arc/metrics/arc_metrics_constants.h"
 #include "ash/components/arc/mojom/system_ui.mojom-shared.h"
+#include "ash/components/arc/session/arc_bridge_service.h"
+#include "ash/components/arc/session/arc_service_manager.h"
 #include "ash/components/arc/system_ui/arc_system_ui_bridge.h"
 #include "ash/components/login/auth/user_context.h"
 #include "ash/components/settings/cros_settings_names.h"
@@ -1958,7 +1960,7 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// AutotestPrivateGetArcPackageFunction
+// AutotestPrivateGetArcAppFunction
 ///////////////////////////////////////////////////////////////////////////////
 
 AutotestPrivateGetArcAppFunction::~AutotestPrivateGetArcAppFunction() = default;
@@ -2011,6 +2013,51 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// AutotestPrivateGetArcAppKillsFunction
+///////////////////////////////////////////////////////////////////////////////
+
+AutotestPrivateGetArcAppKillsFunction::
+    ~AutotestPrivateGetArcAppKillsFunction() = default;
+
+ExtensionFunction::ResponseAction AutotestPrivateGetArcAppKillsFunction::Run() {
+  DVLOG(1) << "AutotestPrivateGetArcAppKillsFunction";
+
+  arc::ArcServiceManager* arc_service_manager = arc::ArcServiceManager::Get();
+  if (!arc_service_manager)
+    return RespondNow(Error("ARC service manager is not available"));
+
+  arc::ArcBridgeService* arc_bridge_service =
+      arc_service_manager->arc_bridge_service();
+
+  if (!arc_bridge_service)
+    return RespondNow(Error("ARC bridge service is not available"));
+
+  arc::mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc_bridge_service->process(), RequestLowMemoryKillCounts);
+
+  if (!process_instance)
+    return RespondNow(Error("ARC process service is not available"));
+
+  process_instance->RequestLowMemoryKillCounts(base::BindOnce(
+      &AutotestPrivateGetArcAppKillsFunction::OnKillCounts, this));
+
+  return RespondLater();
+}
+
+void AutotestPrivateGetArcAppKillsFunction::OnKillCounts(
+    arc::mojom::LowMemoryKillCountsPtr counts) {
+  api::autotest_private::ArcAppKillsDict result;
+  result.oom = counts->guest_oom;
+  result.lmkd_foreground = counts->lmkd_foreground;
+  result.lmkd_perceptible = counts->lmkd_perceptible;
+  result.lmkd_cached = counts->lmkd_cached;
+  result.pressure_foreground = counts->pressure_foreground;
+  result.pressure_perceptible = counts->pressure_perceptible;
+  result.pressure_cached = counts->pressure_cached;
+  Respond(OneArgument(base::Value::FromUniquePtrValue(result.ToValue())));
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // AutotestPrivateGetArcPackageFunction
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index cebc7e3..bbb9e39 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "ash/components/arc/mojom/process.mojom.h"
 #include "ash/display/screen_orientation_controller.h"
 #include "ash/public/cpp/assistant/assistant_state.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
@@ -342,6 +343,17 @@
   ResponseAction Run() override;
 };
 
+class AutotestPrivateGetArcAppKillsFunction : public ExtensionFunction {
+ public:
+  DECLARE_EXTENSION_FUNCTION("autotestPrivate.getArcAppKills",
+                             AUTOTESTPRIVATE_GETARCAPPKILLS)
+
+ private:
+  ~AutotestPrivateGetArcAppKillsFunction() override;
+  ResponseAction Run() override;
+  void OnKillCounts(arc::mojom::LowMemoryKillCountsPtr counts);
+};
+
 class AutotestPrivateGetArcPackageFunction : public ExtensionFunction {
  public:
   DECLARE_EXTENSION_FUNCTION("autotestPrivate.getArcPackage",
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
index f5ef28dc..964609a 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_apitest.cc
@@ -7,11 +7,14 @@
 #include <memory>
 
 #include "ash/components/arc/arc_prefs.h"
+#include "ash/components/arc/session/arc_bridge_service.h"
+#include "ash/components/arc/session/arc_service_manager.h"
 #include "ash/components/arc/session/connection_holder.h"
 #include "ash/components/arc/test/arc_util_test_support.h"
 #include "ash/components/arc/test/connection_holder_util.h"
 #include "ash/components/arc/test/fake_app_instance.h"
 #include "ash/components/arc/test/fake_arc_session.h"
+#include "ash/components/arc/test/fake_process_instance.h"
 #include "ash/public/cpp/holding_space/holding_space_prefs.h"
 #include "ash/public/cpp/overview_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
@@ -153,11 +156,39 @@
       true /* sync */));
   app_instance->SendRefreshPackageList(std::move(packages));
 
+  arc::FakeProcessInstance fake_process_instance;
+  arc::ArcServiceManager::Get()->arc_bridge_service()->process()->SetInstance(
+      &fake_process_instance);
+  fake_process_instance.set_request_low_memory_kill_counts_response(
+      arc::mojom::LowMemoryKillCounts::New(1,    // oom.
+                                           2,    // lmkd_foreground.
+                                           3,    // lmkd_perceptible.
+                                           4,    // lmkd_cached.
+                                           5,    // pressure_foreground.
+                                           6,    // pressure_perceptible.
+                                           7));  // pressure_cached.
+
   ASSERT_TRUE(RunAutotestPrivateExtensionTest("arcEnabled")) << message_;
 
   arc::SetArcPlayStoreEnabledForProfile(profile(), false);
 }
 
+IN_PROC_BROWSER_TEST_F(AutotestPrivateApiTest, AutotestPrivateArcProcess) {
+  arc::FakeProcessInstance fake_process_instance;
+  arc::ArcServiceManager::Get()->arc_bridge_service()->process()->SetInstance(
+      &fake_process_instance);
+  fake_process_instance.set_request_low_memory_kill_counts_response(
+      arc::mojom::LowMemoryKillCounts::New(1,    // oom.
+                                           2,    // lmkd_foreground.
+                                           3,    // lmkd_perceptible.
+                                           4,    // lmkd_cached.
+                                           5,    // pressure_foreground.
+                                           6,    // pressure_perceptible.
+                                           7));  // pressure_cached.
+
+  ASSERT_TRUE(RunAutotestPrivateExtensionTest("arcProcess")) << message_;
+}
+
 IN_PROC_BROWSER_TEST_F(AutotestPrivateApiTest, ScrollableShelfAPITest) {
   ASSERT_TRUE(RunAutotestPrivateExtensionTest("scrollableShelf")) << message_;
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
index 4e280cef..501b7e97 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -777,6 +777,7 @@
       base::BindRepeating(&FileManagerPrivateApiDlpTest::SetDlpRulesManager,
                           base::Unretained(this)));
   ASSERT_TRUE(policy::DlpRulesManagerFactory::GetForPrimaryProfile());
+  EXPECT_CALL(*mock_rules_manager_, IsFilesPolicyEnabled).Times(3);
 
   AddLocalFileSystem(browser()->profile(), temp_dir_.GetPath());
 
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/BUILD.gn b/chrome/browser/chromeos/extensions/telemetry/api/BUILD.gn
index 75202463..b3f9644 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/BUILD.gn
+++ b/chrome/browser/chromeos/extensions/telemetry/api/BUILD.gn
@@ -37,8 +37,6 @@
     "//chrome/browser/ui",
     "//chrome/common/chromeos/extensions",
     "//chrome/common/chromeos/extensions/api",
-    "//components/security_state/content",
-    "//components/security_state/core",
     "//components/user_manager",
     "//content/public/browser",
     "//extensions/browser",
@@ -89,13 +87,10 @@
     "//chromeos/dbus",
     "//chromeos/dbus/debug_daemon",
     "//components/user_manager",
-    "//content/test:test_support",
     "//extensions:test_support",
     "//extensions/browser",
     "//extensions/browser:test_support",
     "//extensions/common",
-    "//net",
-    "//net:test_support",
     "//url",
   ]
 }
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate.cc b/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate.cc
index 41e0ff24..af387f2 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate.cc
@@ -17,8 +17,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h"
-#include "components/security_state/content/content_utils.h"
-#include "components/security_state/core/security_state.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/web_contents.h"
@@ -72,8 +70,8 @@
       return;
     }
 
-    if (!IsPwaUiOpenAndSecure(context, extension)) {
-      std::move(callback).Run("Companion PWA UI is not open or not secure");
+    if (!IsPwaUiOpen(context, extension)) {
+      std::move(callback).Run("Companion PWA UI is not open");
       return;
     }
 
@@ -99,8 +97,8 @@
     return user_manager::UserManager::Get()->IsCurrentUserOwner();
   }
 
-  bool IsPwaUiOpenAndSecure(content::BrowserContext* context,
-                            const extensions::Extension* extension) {
+  bool IsPwaUiOpen(content::BrowserContext* context,
+                   const extensions::Extension* extension) {
     Profile* profile = Profile::FromBrowserContext(context);
 
     const auto* externally_connectable_info =
@@ -118,13 +116,7 @@
             target_tab_strip->GetWebContentsAt(i);
         if (externally_connectable_info->matches.MatchesURL(
                 target_contents->GetLastCommittedURL())) {
-          // Ensure the PWA URL connection is secure (e.g. valid certificate).
-          const auto visible_security_state =
-              security_state::GetVisibleSecurityState(target_contents);
-          return security_state::GetSecurityLevel(
-                     *visible_security_state,
-                     /*used_policy_installed_certificate=*/false) ==
-                 security_state::SecurityLevel::SECURE;
+          return true;
         }
       }
     }
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc b/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc
index 153d0aa1..e817cd7 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/api_guard_delegate_unittest.cc
@@ -16,16 +16,9 @@
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "components/user_manager/user.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/ssl_status.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_urls.h"
-#include "net/base/net_errors.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/x509_certificate.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -51,7 +44,7 @@
 const std::vector<ExtensionInfoTestParams> kAllExtensionInfoTestParams{
     ExtensionInfoTestParams(
         /*extension_id=*/"gogonhoemckpdpadfnjnpgbjpbjnodgc",
-        /*pwa_page_url=*/"https://www.google.com",
+        /*pwa_page_url=*/"http://www.google.com",
         /*matches_origin=*/"*://www.google.com/*",
         /*manufacturer=*/"HP"),  // TODO(http://b/237059912): Refactor this as
                                  // soon as it becomes a set.
@@ -143,24 +136,6 @@
         hardware_info_delegate_factory_.get());
   }
 
-  void OpenPwaUrlAndSetCertificateWithStatus(net::CertStatus cert_status) {
-    const base::FilePath certs_dir = net::GetTestCertsDirectory();
-    scoped_refptr<net::X509Certificate> test_cert(
-        net::ImportCertFromFile(certs_dir, "ok_cert.pem"));
-    ASSERT_TRUE(test_cert);
-
-    // Open the PWA page url and set valid certificate to bypass the
-    // IsPwaUiOpenAndSecure() check.
-    AddTab(browser(), GURL(pwa_page_url()));
-
-    // AddTab() adds a new tab at index 0.
-    auto* web_contents = browser()->tab_strip_model()->GetWebContentsAt(0);
-    auto* entry = web_contents->GetController().GetVisibleEntry();
-    content::SSLStatus& ssl = entry->GetSSL();
-    ssl.certificate = test_cert;
-    ssl.cert_status = cert_status;
-  }
-
  private:
   void CreateExtension() {
     extension_ =
@@ -207,24 +182,12 @@
                                    future.GetCallback());
 
   ASSERT_TRUE(future.Wait());
-  EXPECT_EQ("Companion PWA UI is not open or not secure", future.Get());
-}
-
-TEST_P(ApiGuardDelegateTest, PwaIsOpenButNotSecure) {
-  OpenPwaUrlAndSetCertificateWithStatus(
-      /*cert_status=*/net::CERT_STATUS_INVALID);
-
-  auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
-  base::test::TestFuture<std::string> future;
-  api_guard_delegate->CanAccessApi(profile(), extension(),
-                                   future.GetCallback());
-
-  ASSERT_TRUE(future.Wait());
-  EXPECT_EQ("Companion PWA UI is not open or not secure", future.Get());
+  EXPECT_EQ("Companion PWA UI is not open", future.Get());
 }
 
 TEST_P(ApiGuardDelegateTest, ManufacturerNotAllowed) {
-  OpenPwaUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
+  // Open the PWA page url to bypass IsPwaUiOpen() check.
+  AddTab(browser(), GURL(pwa_page_url()));
 
   // Make sure device manufacturer is not allowed.
   SetDeviceManufacturer("GOOGLE");
@@ -240,7 +203,8 @@
 }
 
 TEST_P(ApiGuardDelegateTest, NoError) {
-  OpenPwaUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
+  // Open the PWA page url to bypass IsPwaUiOpen() check.
+  AddTab(browser(), GURL(pwa_page_url()));
 
   auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
   base::test::TestFuture<std::string> future;
@@ -298,30 +262,7 @@
                                    future.GetCallback());
 
   ASSERT_TRUE(future.Wait());
-  EXPECT_EQ("Companion PWA UI is not open or not secure", future.Get());
-}
-
-TEST_P(ApiGuardDelegateAffiliatedUserTest, PwaIsOpenButNotSecure) {
-  {
-    extensions::ExtensionManagementPrefUpdater<
-        sync_preferences::TestingPrefServiceSyncable>
-        updater(profile()->GetTestingPrefService());
-    // Make sure the extension is marked as force-installed.
-    updater.SetIndividualExtensionAutoInstalled(
-        extension_id(), extension_urls::kChromeWebstoreUpdateURL,
-        /*forced=*/true);
-  }
-
-  OpenPwaUrlAndSetCertificateWithStatus(
-      /*cert_status=*/net::CERT_STATUS_INVALID);
-
-  auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
-  base::test::TestFuture<std::string> future;
-  api_guard_delegate->CanAccessApi(profile(), extension(),
-                                   future.GetCallback());
-
-  ASSERT_TRUE(future.Wait());
-  EXPECT_EQ("Companion PWA UI is not open or not secure", future.Get());
+  EXPECT_EQ("Companion PWA UI is not open", future.Get());
 }
 
 TEST_P(ApiGuardDelegateAffiliatedUserTest, ManufacturerNotAllowed) {
@@ -335,7 +276,8 @@
         /*forced=*/true);
   }
 
-  OpenPwaUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
+  // Open the PWA page url to bypass IsPwaUiOpen() check.
+  AddTab(browser(), GURL(pwa_page_url()));
 
   // Make sure device manufacturer is not allowed.
   SetDeviceManufacturer("GOOGLE");
@@ -361,7 +303,8 @@
         /*forced=*/true);
   }
 
-  OpenPwaUrlAndSetCertificateWithStatus(/*cert_status=*/net::OK);
+  // Open the PWA page url to bypass IsPwaUiOpen() check.
+  AddTab(browser(), GURL(pwa_page_url()));
 
   auto api_guard_delegate = ApiGuardDelegate::Factory::Create();
   base::test::TestFuture<std::string> future;
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_api_guard_function_browsertest.cc b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_api_guard_function_browsertest.cc
index dbf32ce..c21750bf 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_api_guard_function_browsertest.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_api_guard_function_browsertest.cc
@@ -17,11 +17,7 @@
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/test/browser_test.h"
-#include "content/public/test/content_mock_cert_verifier.h"
-#include "net/base/net_errors.h"
-#include "net/cert/x509_certificate.h"
 #include "net/dns/mock_host_resolver.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -330,9 +326,7 @@
     : public BaseTelemetryExtensionBrowserTest {
  public:
   TelemetryExtensionApiGuardRealDelegateBrowserTest()
-      : fake_hardware_info_delegate_factory_("HP"),
-        https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
-    https_server_.ServeFilesFromSourceDirectory(GetChromeTestDataDir());
+      : fake_hardware_info_delegate_factory_("HP") {
     // Make sure device manufacturer is allowlisted.
     HardwareInfoDelegate::Factory::SetForTesting(
         &fake_hardware_info_delegate_factory_);
@@ -345,21 +339,6 @@
       const TelemetryExtensionApiGuardRealDelegateBrowserTest&) = delete;
 
   // BaseTelemetryExtensionBrowserTest:
-  void SetUp() override {
-    ASSERT_TRUE(https_server_.InitializeAndListen());
-
-    BaseTelemetryExtensionBrowserTest::SetUp();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    BaseTelemetryExtensionBrowserTest::SetUpCommandLine(command_line);
-
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        chromeos::switches::kTelemetryExtensionPwaOriginOverrideForTesting,
-        pwa_page_url());
-    mock_cert_verifier_.SetUpCommandLine(command_line);
-  }
-
   void SetUpOnMainThread() override {
     // Skip BaseTelemetryExtensionBrowserTest::SetUpOnMainThread() as it sets up
     // a FakeApiGuardDelegate instance.
@@ -369,8 +348,6 @@
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::make_unique<ash::FakeChromeUserManager>());
 
-    https_server_.StartAcceptingConnections();
-
     // This is needed when navigating to a network URL (e.g.
     // ui_test_utils::NavigateToURL). Rules can only be added before
     // BrowserTestBase::InitializeNetworkProcess() is called because host
@@ -386,53 +363,17 @@
         GetFakeUserManager()->GetActiveUser()->GetAccountId());
     user_manager_enabler_.reset();
 
-    ASSERT_TRUE(https_server_.ShutdownAndWaitUntilComplete());
-
     BaseTelemetryExtensionBrowserTest::TearDownOnMainThread();
   }
 
-  void SetUpInProcessBrowserTestFixture() override {
-    BaseTelemetryExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
-
-    mock_cert_verifier_.SetUpInProcessBrowserTestFixture();
-  }
-
-  void TearDownInProcessBrowserTestFixture() override {
-    mock_cert_verifier_.TearDownInProcessBrowserTestFixture();
-
-    BaseTelemetryExtensionBrowserTest::TearDownInProcessBrowserTestFixture();
-  }
-
-  content::ContentMockCertVerifier::CertVerifier* mock_cert_verifier() {
-    return mock_cert_verifier_.mock_cert_verifier();
-  }
-
-  void SetUpMockCertVerifierForHttpsServer() {
-    scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate());
-    net::CertVerifyResult verify_result;
-    verify_result.is_issued_by_known_root = true;
-    verify_result.verified_cert = cert;
-    verify_result.cert_status = net::OK;
-
-    mock_cert_verifier()->AddResultForCert(cert, verify_result, net::OK);
-  }
-
  protected:
   ash::FakeChromeUserManager* GetFakeUserManager() const {
     return static_cast<ash::FakeChromeUserManager*>(
         user_manager::UserManager::Get());
   }
 
-  GURL GetPwaGURL() const { return https_server_.GetURL("/ssl/google.html"); }
-
-  // BaseTelemetryExtensionBrowserTest:
-  std::string pwa_page_url() const override { return GetPwaGURL().spec(); }
-  std::string matches_origin() const override { return GetPwaGURL().spec(); }
-
   FakeHardwareInfoDelegate::Factory fake_hardware_info_delegate_factory_;
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
-  net::EmbeddedTestServer https_server_;
-  content::ContentMockCertVerifier mock_cert_verifier_;
 };
 
 // Smoke test to verify that real ApiGuardDelegate works in prod.
@@ -446,9 +387,7 @@
   user_manager->SwitchActiveUser(account_id);
   user_manager->SetOwnerId(account_id);
 
-  SetUpMockCertVerifierForHttpsServer();
-
-  // Make sure PWA UI is open and secure.
+  // Make sure PWA UI is open.
   auto* pwa_page_rfh =
       ui_test_utils::NavigateToURL(browser(), GURL(pwa_page_url()));
   ASSERT_TRUE(pwa_page_rfh);
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.h b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.h
index 395a81c..cd98568 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.h
+++ b/chrome/browser/chromeos/extensions/telemetry/api/base_telemetry_extension_browser_test.h
@@ -30,8 +30,8 @@
  protected:
   std::string extension_id() const;
   std::string public_key() const;
-  virtual std::string pwa_page_url() const;
-  virtual std::string matches_origin() const;
+  std::string pwa_page_url() const;
+  std::string matches_origin() const;
   void CreateExtensionAndRunServiceWorker(
       const std::string& service_worker_content);
   virtual std::string GetManifestFile(const std::string& matches_origin);
diff --git a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
index a1ace85..a238761 100644
--- a/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
+++ b/chrome/browser/chromeos/extensions/telemetry/api/telemetry_extension_capabilities_browser_test.cc
@@ -174,7 +174,7 @@
   const auto extension_info = GetChromeOSExtensionInfoForId(extension_id());
   EXPECT_EQ(kPwaOriginOverride, extension_info.pwa_origin);
 
-  // Open the PWA page url to bypass IsPwaUiOpenAndSecure() check.
+  // Open the PWA page url to bypass IsPwaUiOpen() check.
   ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), GURL(kPwaPageUrl)));
 
   // Start listening on the extension.
diff --git a/chrome/browser/extensions/api/settings_private/generated_prefs.cc b/chrome/browser/extensions/api/settings_private/generated_prefs.cc
index ba6944d..f9704d6 100644
--- a/chrome/browser/extensions/api/settings_private/generated_prefs.cc
+++ b/chrome/browser/extensions/api/settings_private/generated_prefs.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/extensions/api/settings_private/generated_pref.h"
 #include "chrome/browser/extensions/api/settings_private/prefs_util_enums.h"
 #include "chrome/browser/password_manager/generated_password_leak_detection_pref.h"
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
 #include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h"
 #include "chrome/common/extensions/api/settings_private.h"
 #include "components/content_settings/core/common/pref_names.h"
@@ -104,7 +103,6 @@
       std::make_unique<safe_browsing::GeneratedSafeBrowsingPref>(profile_);
   prefs_[content_settings::kGeneratedNotificationPref] =
       std::make_unique<content_settings::GeneratedNotificationPref>(profile_);
-  prefs_[kGeneratedFlocPref] = std::make_unique<GeneratedFlocPref>(profile_);
 }
 
 }  // namespace settings_private
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 1369ee773..0ed4b54c 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
 #include "chrome/browser/password_manager/generated_password_leak_detection_pref.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/generated_safe_browsing_pref.h"
 #include "chrome/common/chrome_features.h"
@@ -296,8 +295,6 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_allowlist)[::prefs::kPrivacySandboxPageViewed] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_allowlist)[::kGeneratedFlocPref] =
-      settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
   // Security page
   (*s_allowlist)[::kGeneratedPasswordLeakDetectionPref] =
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 3ec9d7e..4eb3e84 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -425,6 +425,11 @@
     "expiry_milestone": 106
   },
   {
+      "name": "autofill-enable-new-card-unmask-prompt-view",
+      "owners": [ "eic", "bling-flags@google.com" ],
+      "expiry_milestone": 109
+  },
+  {
     "name": "autofill-enable-offer-notification-for-promo-codes",
     "owners": [ "jsaul@google.com", "siyua" ],
     "expiry_milestone": 105
@@ -2128,6 +2133,11 @@
     "expiry_milestone": 108
   },
   {
+    "name": "enable-family-info-feedback",
+    "owners": ["fernandex", "chrome-kids-eng@google.com"],
+    "expiry_milestone": 110
+  },
+  {
       "name": "enable-favicon-passwords",
       "owners": [ "veronguyen", "gambard" ],
       "expiry_milestone": 105
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 3fcb284..7d227b85 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3295,6 +3295,11 @@
 const char kEnableCommandLineOnNoRootedDescription[] =
     "Enable reading command line file on non-rooted devices (DANGEROUS).";
 
+const char kEnableFamilyInfoFeedbackName[] =
+    "Enable feedback from FamilyLink (Android)";
+const char kEnableFamilyInfoFeedbackDescription[] =
+    "Enable FamilyLink feedback source in Chrome Settings feedback";
+
 const char kExploreSitesName[] = "Explore websites";
 const char kExploreSitesDescription[] =
     "Enables portal from new tab page to explore websites.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index a83953f9..7ee030a1 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1850,6 +1850,9 @@
 extern const char kEnableCommandLineOnNonRootedName[];
 extern const char kEnableCommandLineOnNoRootedDescription[];
 
+extern const char kEnableFamilyInfoFeedbackName[];
+extern const char kEnableFamilyInfoFeedbackDescription[];
+
 extern const char kExploreSitesName[];
 extern const char kExploreSitesDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 175b9d58..f8f8dc24 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/performance_hints/performance_hints_features.h"
 #include "chrome/browser/push_messaging/push_messaging_features.h"
 #include "chrome/browser/share/share_features.h"
+#include "chrome/browser/signin/signin_features.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/video_tutorials/switches.h"
 #include "chrome/common/chrome_features.h"
@@ -226,6 +227,7 @@
     &kDuetTabStripIntegrationAndroid,
     &kDynamicColorAndroid,
     &kDynamicColorButtonsAndroid,
+    &kEnableFamilyInfoFeedback,
     &kExperimentsForAgsa,
     &kExploreSites,
     &kFixedUmaSessionResumeOrder,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 076f961e..994e994 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -339,6 +339,7 @@
     public static final String ELIDE_PRIORITIZATION_OF_PRE_NATIVE_BOOTSTRAP_TASKS =
             "ElidePrioritizationOfPreNativeBootstrapTasks";
     public static final String ENABLE_AUTOMATIC_SNOOZE = "EnableAutomaticSnooze";
+    public static final String ENABLE_FAMILY_INFO_FEEDBACK = "EnableFamilyInfoFeedback";
     public static final String ELASTIC_OVERSCROLL = "ElasticOverscroll";
     public static final String EXPERIMENTS_FOR_AGSA = "ExperimentsForAgsa";
     public static final String EXPLICIT_LANGUAGE_ASK = "ExplicitLanguageAsk";
diff --git a/chrome/browser/language/android/java/res/layout/app_language_prompt_more_languages.xml b/chrome/browser/language/android/java/res/layout/app_language_prompt_more_languages.xml
index 52e612e..41fb9e8 100644
--- a/chrome/browser/language/android/java/res/layout/app_language_prompt_more_languages.xml
+++ b/chrome/browser/language/android/java/res/layout/app_language_prompt_more_languages.xml
@@ -26,7 +26,7 @@
         android:id="@+id/more_languages_button"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:text="@string/languages_select_other"
+        android:text="@string/languages_more_languages"
         style="@style/TextAppearance.Button.Text.Blue" />
 
 </LinearLayout>
diff --git a/chrome/browser/password_manager/android/password_store_android_backend.cc b/chrome/browser/password_manager/android/password_store_android_backend.cc
index 553e5f1..84476b5 100644
--- a/chrome/browser/password_manager/android/password_store_android_backend.cc
+++ b/chrome/browser/password_manager/android/password_store_android_backend.cc
@@ -440,6 +440,9 @@
 void PasswordStoreAndroidBackend::AddLoginAsync(
     const PasswordForm& form,
     PasswordChangesOrErrorReply callback) {
+  // TODO(crbug.com/1324588): remove this check
+  CHECK(!form.blocked_by_user ||
+        (form.username_value.empty() && form.password_value.empty()));
   JobId job_id =
       bridge_->AddLogin(form, GetAccount(sync_delegate_->GetSyncingAccount()));
   QueueNewJob(job_id, std::move(callback), MetricInfix("AddLoginAsync"));
@@ -448,6 +451,9 @@
 void PasswordStoreAndroidBackend::UpdateLoginAsync(
     const PasswordForm& form,
     PasswordChangesOrErrorReply callback) {
+  // TODO(crbug.com/1324588): remove this check
+  CHECK(!form.blocked_by_user ||
+        (form.username_value.empty() && form.password_value.empty()));
   JobId job_id = bridge_->UpdateLogin(
       form, GetAccount(sync_delegate_->GetSyncingAccount()));
   QueueNewJob(job_id, std::move(callback), MetricInfix("UpdateLoginAsync"));
diff --git a/chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.cc b/chrome/browser/policy/status_provider/cloud_policy_core_status_provider.cc
similarity index 90%
rename from chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.cc
rename to chrome/browser/policy/status_provider/cloud_policy_core_status_provider.cc
index 11cff2f..41a7cb7 100644
--- a/chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.cc
+++ b/chrome/browser/policy/status_provider/cloud_policy_core_status_provider.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/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h"
+#include "chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h"
 
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h b/chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h
similarity index 83%
rename from chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h
rename to chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h
index 9683be70..59930f8f 100644
--- a/chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h
+++ b/chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
 
 #include "components/policy/core/browser/webui/policy_status_provider.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -38,4 +38,4 @@
   raw_ptr<policy::CloudPolicyCore> core_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_CLOUD_POLICY_CORE_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.cc b/chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.cc
similarity index 80%
rename from chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.cc
rename to chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.cc
index dfcb75d..3d5aac87 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.cc
+++ b/chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.cc
@@ -2,10 +2,10 @@
 // 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/policy/status_provider/device_active_directory_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.h"
 
 #include "base/values.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 
 DeviceActiveDirectoryPolicyStatusProvider::
     DeviceActiveDirectoryPolicyStatusProvider(
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.h b/chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.h
similarity index 72%
rename from chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.h
rename to chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.h
index be6bfa4..ce59bca1 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.h
+++ b/chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.h
@@ -2,12 +2,12 @@
 // 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_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
 
 #include <string>
 
-#include "chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h"
 
 namespace base {
 class DictionaryValue;
@@ -39,4 +39,4 @@
   std::string enterprise_domain_manager_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc b/chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc
similarity index 83%
rename from chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc
rename to chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc
index 6d1ea57..5a347e1b 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc
+++ b/chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc
@@ -2,13 +2,13 @@
 // 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/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
+#include "chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
 
 #include <string>
 
 #include "base/values.h"
 #include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 
 DeviceCloudPolicyStatusProviderChromeOS::
     DeviceCloudPolicyStatusProviderChromeOS(
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h b/chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h
similarity index 71%
rename from chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h
rename to chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h
index dfbceaf..339dd09 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h
+++ b/chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h
@@ -2,10 +2,10 @@
 // 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_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
 
-#include "chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h"
+#include "chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h"
 
 namespace base {
 class DictionaryValue;
@@ -36,4 +36,4 @@
   std::string enterprise_domain_manager_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.cc b/chrome/browser/policy/status_provider/device_local_account_policy_status_provider.cc
similarity index 89%
rename from chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.cc
rename to chrome/browser/policy/status_provider/device_local_account_policy_status_provider.cc
index f39e82ea..88ced68 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.cc
+++ b/chrome/browser/policy/status_provider/device_local_account_policy_status_provider.cc
@@ -2,10 +2,10 @@
 // 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/policy/status_provider/device_local_account_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/device_local_account_policy_status_provider.h"
 
 #include "base/values.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 #include "components/policy/core/browser/cloud/message_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.h b/chrome/browser/policy/status_provider/device_local_account_policy_status_provider.h
similarity index 84%
rename from chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.h
rename to chrome/browser/policy/status_provider/device_local_account_policy_status_provider.h
index a07f12ad..ec4eb3c 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.h
+++ b/chrome/browser/policy/status_provider/device_local_account_policy_status_provider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
 
 #include <string>
 
@@ -47,4 +47,4 @@
   policy::DeviceLocalAccountPolicyService* service_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_LOCAL_ACCOUNT_POLICY_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.cc b/chrome/browser/policy/status_provider/device_policy_status_provider_lacros.cc
similarity index 87%
rename from chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.cc
rename to chrome/browser/policy/status_provider/device_policy_status_provider_lacros.cc
index 1457d37..e77eeb0 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.cc
+++ b/chrome/browser/policy/status_provider/device_policy_status_provider_lacros.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/ui/webui/policy/status_provider/device_policy_status_provider_lacros.h"
+#include "chrome/browser/policy/status_provider/device_policy_status_provider_lacros.h"
 
 #include <utility>
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.h b/chrome/browser/policy/status_provider/device_policy_status_provider_lacros.h
similarity index 71%
rename from chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.h
rename to chrome/browser/policy/status_provider/device_policy_status_provider_lacros.h
index 2198c03..adf9054 100644
--- a/chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.h
+++ b/chrome/browser/policy/status_provider/device_policy_status_provider_lacros.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
 
 #include "base/values.h"
 #include "components/policy/core/browser/webui/policy_status_provider.h"
@@ -23,4 +23,4 @@
   base::Value::Dict device_policy_status_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_DEVICE_POLICY_STATUS_PROVIDER_LACROS_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/status_provider_util.cc b/chrome/browser/policy/status_provider/status_provider_util.cc
similarity index 96%
rename from chrome/browser/ui/webui/policy/status_provider/status_provider_util.cc
rename to chrome/browser/policy/status_provider/status_provider_util.cc
index 072d99f..4622a4d 100644
--- a/chrome/browser/ui/webui/policy/status_provider/status_provider_util.cc
+++ b/chrome/browser/policy/status_provider/status_provider_util.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/ui/webui/policy/status_provider/status_provider_util.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 
 #include "google_apis/gaia/gaia_auth_util.h"
 #if BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/policy/status_provider/status_provider_util.h b/chrome/browser/policy/status_provider/status_provider_util.h
similarity index 82%
rename from chrome/browser/ui/webui/policy/status_provider/status_provider_util.h
rename to chrome/browser/policy/status_provider/status_provider_util.h
index 4078f7e..472741d 100644
--- a/chrome/browser/ui/webui/policy/status_provider/status_provider_util.h
+++ b/chrome/browser/policy/status_provider/status_provider_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
 
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
@@ -29,4 +29,4 @@
 void GetUserManager(base::DictionaryValue* dict, Profile* profile);
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_STATUS_PROVIDER_UTIL_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/updater_status_provider.cc b/chrome/browser/policy/status_provider/updater_status_provider.cc
similarity index 96%
rename from chrome/browser/ui/webui/policy/status_provider/updater_status_provider.cc
rename to chrome/browser/policy/status_provider/updater_status_provider.cc
index b753316..f790d56 100644
--- a/chrome/browser/ui/webui/policy/status_provider/updater_status_provider.cc
+++ b/chrome/browser/policy/status_provider/updater_status_provider.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/ui/webui/policy/status_provider/updater_status_provider.h"
+#include "chrome/browser/policy/status_provider/updater_status_provider.h"
 
 #include <windows.h>
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/updater_status_provider.h b/chrome/browser/policy/status_provider/updater_status_provider.h
similarity index 77%
rename from chrome/browser/ui/webui/policy/status_provider/updater_status_provider.h
rename to chrome/browser/policy/status_provider/updater_status_provider.h
index b632ae8..10dd94b4 100644
--- a/chrome/browser/ui/webui/policy/status_provider/updater_status_provider.h
+++ b/chrome/browser/policy/status_provider/updater_status_provider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
 
 #include <string>
 
@@ -31,4 +31,4 @@
   base::WeakPtrFactory<UpdaterStatusProvider> weak_factory_{this};
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_UPDATER_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.cc b/chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.cc
similarity index 94%
rename from chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.cc
rename to chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.cc
index 2677d8a..1fe2a6b 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.cc
+++ b/chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.cc
@@ -2,13 +2,13 @@
 // 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/policy/status_provider/user_active_directory_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h"
 
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/ash/policy/active_directory/active_directory_policy_manager.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
 #include "components/policy/core/browser/cloud/message_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.h b/chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h
similarity index 82%
rename from chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.h
rename to chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h
index 02cea50..b5cad3c 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.h
+++ b/chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
 
 #include "components/policy/core/browser/webui/policy_status_provider.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -46,4 +46,4 @@
   Profile* profile_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_ACTIVE_DIRECTORY_POLICY_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.cc b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider.cc
similarity index 83%
rename from chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.cc
rename to chrome/browser/policy/status_provider/user_cloud_policy_status_provider.cc
index 7153e46..ec0f91c9 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.cc
+++ b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider.cc
@@ -2,11 +2,11 @@
 // 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/policy/status_provider/user_cloud_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h"
 
 #include "base/values.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.h b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h
similarity index 72%
rename from chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.h
rename to chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h
index 93098c3e..33d9c02 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.h
+++ b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h
@@ -2,11 +2,11 @@
 // 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_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
 
 #include "base/memory/raw_ptr.h"
-#include "chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h"
+#include "chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h"
 
 class Profile;
 
@@ -37,4 +37,4 @@
   raw_ptr<Profile> profile_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc
similarity index 83%
rename from chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc
rename to chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc
index 223039121..009ab78 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc
+++ b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc
@@ -2,11 +2,11 @@
 // 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/policy/status_provider/user_cloud_policy_status_provider_chromeos.h"
+#include "chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.h"
 
 #include "base/values.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.h b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.h
similarity index 72%
rename from chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.h
rename to chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.h
index a5dd983..b1fc352 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.h
+++ b/chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.h
@@ -2,10 +2,10 @@
 // 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_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
 
-#include "chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h"
 
 class Profile;
 
@@ -38,4 +38,4 @@
   Profile* profile_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_CLOUD_POLICY_STATUS_PROVIDER_CHROMEOS_H_
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.cc b/chrome/browser/policy/status_provider/user_policy_status_provider_lacros.cc
similarity index 91%
rename from chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.cc
rename to chrome/browser/policy/status_provider/user_policy_status_provider_lacros.cc
index 13fad57..4593feca 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.cc
+++ b/chrome/browser/policy/status_provider/user_policy_status_provider_lacros.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.h"
+#include "chrome/browser/policy/status_provider/user_policy_status_provider_lacros.h"
 
 #include "base/time/time.h"
 #include "base/values.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
 #include "components/policy/core/browser/cloud/message_util.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/core/common/policy_loader_lacros.h"
diff --git a/chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.h b/chrome/browser/policy/status_provider/user_policy_status_provider_lacros.h
similarity index 79%
rename from chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.h
rename to chrome/browser/policy/status_provider/user_policy_status_provider_lacros.h
index 8a25c035..d891aea 100644
--- a/chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.h
+++ b/chrome/browser/policy/status_provider/user_policy_status_provider_lacros.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
-#define CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
+#ifndef CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
+#define CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
 
 #include "components/policy/core/browser/webui/policy_status_provider.h"
 
@@ -38,4 +38,4 @@
   raw_ptr<policy::PolicyLoaderLacros> loader_;
 };
 
-#endif  // CHROME_BROWSER_UI_WEBUI_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
+#endif  // CHROME_BROWSER_POLICY_STATUS_PROVIDER_USER_POLICY_STATUS_PROVIDER_LACROS_H_
diff --git a/chrome/browser/privacy_sandbox/generated_floc_pref.cc b/chrome/browser/privacy_sandbox/generated_floc_pref.cc
deleted file mode 100644
index 1db016d29..0000000
--- a/chrome/browser/privacy_sandbox/generated_floc_pref.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/extensions/api/settings_private.h"
-#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
-
-namespace settings_api = extensions::api::settings_private;
-
-const char kGeneratedFlocPref[] = "generated.floc_enabled";
-
-GeneratedFlocPref::GeneratedFlocPref(Profile* profile) : profile_(profile) {
-  user_prefs_registrar_.Init(profile->GetPrefs());
-  user_prefs_registrar_.Add(
-      prefs::kPrivacySandboxApisEnabled,
-      base::BindRepeating(&GeneratedFlocPref::OnSourcePreferencesChanged,
-                          base::Unretained(this)));
-  user_prefs_registrar_.Add(
-      prefs::kPrivacySandboxFlocEnabled,
-      base::BindRepeating(&GeneratedFlocPref::OnSourcePreferencesChanged,
-                          base::Unretained(this)));
-}
-
-extensions::settings_private::SetPrefResult GeneratedFlocPref::SetPref(
-    const base::Value* value) {
-  if (!value->is_bool())
-    return extensions::settings_private::SetPrefResult::PREF_TYPE_MISMATCH;
-
-  // If the Privacy Sandbox APIs pref is disabled for any reason, the generated
-  // pref cannot be changed.
-  if (!profile_->GetPrefs()->GetBoolean(prefs::kPrivacySandboxApisEnabled))
-    return extensions::settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
-
-  profile_->GetPrefs()->SetBoolean(prefs::kPrivacySandboxFlocEnabled,
-                                   value->GetBool());
-
-  return extensions::settings_private::SetPrefResult::SUCCESS;
-}
-
-std::unique_ptr<extensions::api::settings_private::PrefObject>
-GeneratedFlocPref::GetPrefObject() const {
-  // Disable FLoC control while OT not active.
-  // TODO(crbug.com/1287951): Perform cleanup / adjustment as required.
-  auto floc_pref_object = std::make_unique<settings_api::PrefObject>();
-  floc_pref_object->key = kGeneratedFlocPref;
-  floc_pref_object->type = settings_api::PREF_TYPE_BOOLEAN;
-  floc_pref_object->value = std::make_unique<base::Value>(false);
-  floc_pref_object->user_control_disabled = std::make_unique<bool>(true);
-
-  return floc_pref_object;
-}
-
-void GeneratedFlocPref::OnSourcePreferencesChanged() {
-  NotifyObservers(kGeneratedFlocPref);
-}
diff --git a/chrome/browser/privacy_sandbox/generated_floc_pref.h b/chrome/browser/privacy_sandbox/generated_floc_pref.h
deleted file mode 100644
index 85e75c44..0000000
--- a/chrome/browser/privacy_sandbox/generated_floc_pref.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PRIVACY_SANDBOX_GENERATED_FLOC_PREF_H_
-#define CHROME_BROWSER_PRIVACY_SANDBOX_GENERATED_FLOC_PREF_H_
-
-#include "base/memory/raw_ptr.h"
-#include "chrome/browser/extensions/api/settings_private/generated_pref.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/prefs/pref_change_registrar.h"
-
-extern const char kGeneratedFlocPref[];
-
-// A generated preference which is used on the chrome://settings/privacySandbox
-// page to drive the FLoC toggle. This preference reflects the effective state
-// of FLoC, which also respects the main Privacy Sandbox pref as an opt out,
-// rather than the state of the underlying FLoC preference.
-class GeneratedFlocPref : public extensions::settings_private::GeneratedPref {
- public:
-  explicit GeneratedFlocPref(Profile* profile);
-
-  // extensions::settings_private::GeneratedPref:
-  extensions::settings_private::SetPrefResult SetPref(
-      const base::Value* value) override;
-  std::unique_ptr<extensions::api::settings_private::PrefObject> GetPrefObject()
-      const override;
-
-  // Called when one of the real preferences this generated pref depends on is
-  // changed.
-  void OnSourcePreferencesChanged();
-
- private:
-  const raw_ptr<Profile> profile_;
-
-  PrefChangeRegistrar user_prefs_registrar_;
-};
-
-#endif  // CHROME_BROWSER_PRIVACY_SANDBOX_GENERATED_FLOC_PREF_H_
diff --git a/chrome/browser/privacy_sandbox/generated_floc_pref_unittest.cc b/chrome/browser/privacy_sandbox/generated_floc_pref_unittest.cc
deleted file mode 100644
index 6d3d180f..0000000
--- a/chrome/browser/privacy_sandbox/generated_floc_pref_unittest.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/privacy_sandbox/generated_floc_pref.h"
-
-#include "chrome/browser/extensions/api/settings_private/generated_pref_test_base.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
-
-namespace settings_private = extensions::settings_private;
-
-typedef settings_private::GeneratedPrefTestBase GeneratedFlocPrefTest;
-
-TEST_F(GeneratedFlocPrefTest, SetPreference) {
-  // Confirm that the backing preference is updated appropriately, or if not,
-  // the appropriate error is returned.
-  auto pref = std::make_unique<GeneratedFlocPref>(profile());
-
-  // Disabling the Privacy Sandbox APIs pref should prevent the generated pref
-  // from being changed, and the backing real pref should not change.
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(false));
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(false));
-  EXPECT_EQ(settings_private::SetPrefResult::PREF_NOT_MODIFIABLE,
-            pref->SetPref(std::make_unique<base::Value>(true).get()));
-  EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxFlocEnabled));
-
-  // Enabling the Privacy Sandbox APIs pref should allow the generated pref to
-  // change, as well as the backing real pref.
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(true));
-  EXPECT_EQ(settings_private::SetPrefResult::SUCCESS,
-            pref->SetPref(std::make_unique<base::Value>(true).get()));
-  EXPECT_TRUE(prefs()->GetBoolean(prefs::kPrivacySandboxFlocEnabled));
-
-  // The pref should only accept boolean values.
-  EXPECT_EQ(settings_private::SetPrefResult::PREF_TYPE_MISMATCH,
-            pref->SetPref(std::make_unique<base::Value>(23).get()));
-
-  // Disabling the Privacy Sandbox APIs pref via management should also prevent
-  // the generated pref & real pref from changing.
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(true));
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(false));
-  prefs()->SetManagedPref(prefs::kPrivacySandboxApisEnabled,
-                          std::make_unique<base::Value>(false));
-
-  EXPECT_EQ(settings_private::SetPrefResult::PREF_NOT_MODIFIABLE,
-            pref->SetPref(std::make_unique<base::Value>(true).get()));
-  EXPECT_FALSE(prefs()->GetBoolean(prefs::kPrivacySandboxFlocEnabled));
-}
-
-TEST_F(GeneratedFlocPrefTest, GetPreference) {
-  // The generated preference should correctly reflect the effective state
-  // of FLoC, rather than simply the real pref.
-  auto pref = std::make_unique<GeneratedFlocPref>(profile());
-
-  // When the Privacy Sandbox APIs pref is disabled, the generated pref should
-  // be disabled with user control also disabled, regardless of the real FLoC
-  // pref state.
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(false));
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(false));
-  EXPECT_FALSE(pref->GetPrefObject()->value->GetBool());
-  EXPECT_TRUE(*pref->GetPrefObject()->user_control_disabled);
-
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(true));
-  EXPECT_FALSE(pref->GetPrefObject()->value->GetBool());
-  EXPECT_TRUE(*pref->GetPrefObject()->user_control_disabled);
-
-  // When the Privacy Sandbox APIs pref is enabled, the generated pref should
-  // follow the state of the real FLoC pref, and user control should be enabled.
-  // TODO(crbug.com/1287951): User control disabled while OT is not active.
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(true));
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(true));
-  EXPECT_FALSE(pref->GetPrefObject()->value->GetBool());
-  EXPECT_TRUE(*pref->GetPrefObject()->user_control_disabled);
-
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(false));
-  EXPECT_FALSE(pref->GetPrefObject()->value->GetBool());
-  EXPECT_TRUE(*pref->GetPrefObject()->user_control_disabled);
-
-  // The generated pref should inherit the management state of the Privacy
-  // Sandbox APIs pref.
-  // TODO(crbug.com/1287951): No managenent state while OT not active.
-  prefs()->SetManagedPref(prefs::kPrivacySandboxApisEnabled,
-                          std::make_unique<base::Value>(false));
-  EXPECT_EQ(settings_api::Enforcement::ENFORCEMENT_NONE,
-            pref->GetPrefObject()->enforcement);
-  EXPECT_EQ(settings_api::ControlledBy::CONTROLLED_BY_NONE,
-            pref->GetPrefObject()->controlled_by);
-}
-
-TEST_F(GeneratedFlocPrefTest, NotifyPrefUpdates) {
-  // Confirm that when the relevant real preferences change, the generated
-  // pref notifies observers it has been updated.
-  auto pref = std::make_unique<GeneratedFlocPref>(profile());
-  prefs()->SetDefaultPrefValue(prefs::kPrivacySandboxApisEnabled,
-                               base::Value(false));
-  prefs()->SetDefaultPrefValue(prefs::kPrivacySandboxFlocEnabled,
-                               base::Value(false));
-
-  settings_private::TestGeneratedPrefObserver test_observer;
-  pref->AddObserver(&test_observer);
-
-  prefs()->SetUserPref(prefs::kPrivacySandboxApisEnabled,
-                       std::make_unique<base::Value>(true));
-  EXPECT_EQ(test_observer.GetUpdatedPrefName(), kGeneratedFlocPref);
-  test_observer.Reset();
-
-  prefs()->SetUserPref(prefs::kPrivacySandboxFlocEnabled,
-                       std::make_unique<base::Value>(true));
-  EXPECT_EQ(test_observer.GetUpdatedPrefName(), kGeneratedFlocPref);
-  test_observer.Reset();
-}
diff --git a/chrome/browser/resources/access_code_cast/BUILD.gn b/chrome/browser/resources/access_code_cast/BUILD.gn
index d2f4ab7..dd8e0a7 100644
--- a/chrome/browser/resources/access_code_cast/BUILD.gn
+++ b/chrome/browser/resources/access_code_cast/BUILD.gn
@@ -57,7 +57,8 @@
 generate_grd("build_grd") {
   input_files = [ "index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   deps = [ ":build_ts" ]
 
   grd_prefix = "access_code_cast"
diff --git a/chrome/browser/resources/app_service_internals/BUILD.gn b/chrome/browser/resources/app_service_internals/BUILD.gn
index 1693618a..6dc265d 100644
--- a/chrome/browser/resources/app_service_internals/BUILD.gn
+++ b/chrome/browser/resources/app_service_internals/BUILD.gn
@@ -50,7 +50,8 @@
   deps = [ ":build_ts" ]
   input_files = [ "index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 
   grd_prefix = "app_service_internals"
   out_grd = resources_grd_file
diff --git a/chrome/browser/resources/app_settings/BUILD.gn b/chrome/browser/resources/app_settings/BUILD.gn
index 669b3815..6b03ab0 100644
--- a/chrome/browser/resources/app_settings/BUILD.gn
+++ b/chrome/browser/resources/app_settings/BUILD.gn
@@ -52,7 +52,8 @@
   input_files = [ "web_app_settings.html" ]
   input_files_base_dir = rebase_path(".", "//")
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
 
 grit("resources") {
diff --git a/chrome/browser/resources/bluetooth_internals/BUILD.gn b/chrome/browser/resources/bluetooth_internals/BUILD.gn
index 8be2e22..1e9aca8 100644
--- a/chrome/browser/resources/bluetooth_internals/BUILD.gn
+++ b/chrome/browser/resources/bluetooth_internals/BUILD.gn
@@ -33,29 +33,6 @@
           root_build_dir)
 }
 
-generate_grd("build_grd") {
-  grd_prefix = bluetooth_grd_prefix
-  out_grd = resources_grd_file
-  deps = [
-    ":build_internal_mojo_grdp",
-    ":build_public_mojo_grdp",
-    ":build_ts",
-  ]
-  input_files = [
-    "bluetooth_internals.css",
-    "bluetooth_internals.html",
-    "menu.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  grdp_files = [
-    public_mojo_grdp_file,
-    internals_mojo_grdp_file,
-  ]
-
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 # TODO(crbug.com/1337318): This page should be converted to TypeScript but this
 # will be a lot of work. Passing the JavaScript files through the TypeScript
 # compiler will provide basic static checks (e.g. syntax) without validating
@@ -109,3 +86,27 @@
   ]
   output_dir = "$root_gen_dir/chrome"
 }
+
+generate_grd("build_grd") {
+  grd_prefix = bluetooth_grd_prefix
+  out_grd = resources_grd_file
+  deps = [
+    ":build_internal_mojo_grdp",
+    ":build_public_mojo_grdp",
+    ":build_ts",
+  ]
+  input_files = [
+    "bluetooth_internals.css",
+    "bluetooth_internals.html",
+    "menu.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  grdp_files = [
+    public_mojo_grdp_file,
+    internals_mojo_grdp_file,
+  ]
+
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/bookmarks/BUILD.gn b/chrome/browser/resources/bookmarks/BUILD.gn
index 193ca13..e95bfbe5 100644
--- a/chrome/browser/resources/bookmarks/BUILD.gn
+++ b/chrome/browser/resources/bookmarks/BUILD.gn
@@ -33,25 +33,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  input_files = [
-    "bookmarks.html",
-    "images/folder_open.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [ "bookmarks.rollup.js|bookmarks.js" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-  grd_prefix = "bookmarks"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -117,3 +98,23 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  input_files = [
+    "bookmarks.html",
+    "images/folder_open.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [ "bookmarks.rollup.js|bookmarks.js" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+  grd_prefix = "bookmarks"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
diff --git a/chrome/browser/resources/browser_switch/BUILD.gn b/chrome/browser/resources/browser_switch/BUILD.gn
index 9ad603df..ecc70a6 100644
--- a/chrome/browser/resources/browser_switch/BUILD.gn
+++ b/chrome/browser/resources/browser_switch/BUILD.gn
@@ -27,19 +27,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "browser_switch"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "browser_switch.html",
-    "internals/browser_switch_internals.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 ts_library("build_ts") {
   root_dir = target_gen_dir
   out_dir = "$target_gen_dir/tsc"
@@ -64,6 +51,20 @@
   ]
 }
 
+generate_grd("build_grd") {
+  grd_prefix = "browser_switch"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "browser_switch.html",
+    "internals/browser_switch_internals.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
+
 copy("copy_main") {
   sources = [
     "app.ts",
diff --git a/chrome/browser/resources/browsing_topics/BUILD.gn b/chrome/browser/resources/browsing_topics/BUILD.gn
index e0e01c8..6e411cb 100644
--- a/chrome/browser/resources/browsing_topics/BUILD.gn
+++ b/chrome/browser/resources/browsing_topics/BUILD.gn
@@ -24,18 +24,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "browsing_topics_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [
-    "browsing_topics_internals.html",
-    "browsing_topics_internals.css",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 copy("copy_mojo") {
   deps = [ "//components/browsing_topics/mojom:mojo_bindings_webui_js" ]
   mojom_folder = "$root_gen_dir/mojom-webui/components/browsing_topics/mojom/"
@@ -62,3 +50,16 @@
     ":copy_ts",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "browsing_topics_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [
+    "browsing_topics_internals.html",
+    "browsing_topics_internals.css",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/chrome/browser/resources/chromeos/audio/BUILD.gn b/chrome/browser/resources/chromeos/audio/BUILD.gn
index 2d9141e7..1f8697e 100644
--- a/chrome/browser/resources/chromeos/audio/BUILD.gn
+++ b/chrome/browser/resources/chromeos/audio/BUILD.gn
@@ -59,7 +59,8 @@
     "audio.css",
   ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 
   grd_prefix = "audio"
   out_grd = resources_grd_file
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
index 40f4560..04f148b 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_group.js
@@ -35,7 +35,7 @@
       /** @type {!Array<EmojiVariants>} */
       data: {type: Array, readonly: true},
       /** @type {Object<string,string>} */
-      preferred: {type: Object, value: {}},
+      preferred: {type: Object, value: () => ({})},
       /** @type {boolean} */
       clearable: {type: Boolean, value: false},
       /** @type {string} */
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
index 9ae0fa5..c53dba9 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.html
@@ -252,9 +252,9 @@
   <emoji-search
     class="side-padding"
     id="search-container"
-    emoji-data="[[emojiData]]"
-    emoticon-data="[[emoticonData]]"
+    categories-data="[[categoriesData]]"
     search="{{search}}"
+    lazy-indexing="[[searchLazyIndexing]]"
     on-scroll="onSearchScroll"
     category-metadata="[[getCategoryMetadata(category)]]"
     v2-enabled="[[v2Enabled]]">
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
index 0cfbdd1..22c9282 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_picker.js
@@ -59,10 +59,13 @@
       /** @private {?EmojiGroupData} */
       emojiData: {
         type: Array,
+        value: () => ([]),
         observer: 'onEmojiDataChanged',
       },
+      /** @private {EmojiGroupData} */
+      categoriesData: {type: Array, value: () => ([])},
       /** @type {?EmojiGroupData} */
-      emoticonData: {type: Array, value: []},
+      emoticonData: {type: Array, value: () => ([])},
       /** @private {Object<string,string>} */
       preferenceMapping: {type: Object},
       /** @private {!EmojiGroup} */
@@ -74,6 +77,8 @@
       /** @private {string} */
       search: {type: String, value: '', observer: 'onSearchChanged'},
       /** @private {boolean} */
+      searchLazyIndexing: {type: Boolean, value: true},
+      /** @private {boolean} */
       textSubcategoryBarEnabled: {
         type: Boolean,
         value: false,
@@ -101,8 +106,11 @@
     this.emojiData = [];
 
     // TODO(b/216475720): rename the data structure below for a generic naming.
-    this.emojiHistory = {'group': 'Recently used', 'emoji': []};
-    this.emoticonHistory = {'group': 'Recently used', 'emoji': []};
+    this.emojiHistory = {
+      'group': 'Recently used', 'emoji': [], 'category': CategoryEnum.EMOJI};
+    this.emoticonHistory = {
+      'group': 'Recently used', 'emoji': [],
+      'category': CategoryEnum.EMOTICON};
 
     this.preferenceMapping = {};
 
@@ -199,7 +207,7 @@
             ev => this.onCategoryButtonClick(ev.detail.categoryName));
         this.addEventListener(events.EMOJI_REMAINING_DATA_LOADED, () => {
           this.fetchOrderingData(this.emoticonDataUrl).then((data) => {
-            this.emoticonData = data;
+            this.updateCategoryData(data, CategoryEnum.EMOTICON, true);
             this.dispatchEvent(events.createCustomEvent(
               events.V2_CONTENT_LOADED));
           });
@@ -250,6 +258,44 @@
     });
   }
 
+  /**
+   * Processes a new category data and updates any needed variables and UIs
+   * accordingly.
+   *
+   * @param {!EmojiGroupData} data The category data to be processes.
+   *    Note: category field will be added to the each EmojiGroup in data.
+   * @param {!CategoryEnum} category Category of the data.
+   * @param {boolean} lastPartition True if no future data updates are
+   *      expected.
+   */
+  updateCategoryData(data, category, lastPartition=false) {
+    // TODO(b/233270589): Add category to the underlying data.
+    // Add category field to the data.
+    data.forEach((emojiGroup) => {
+      emojiGroup.category = category;
+    });
+
+    // TODO(b/235418846): Remove the following.
+    // Update the data variable of the category.
+    switch (category) {
+      case CategoryEnum.EMOJI:
+        this.push('emojiData', ...data);
+        break;
+      case CategoryEnum.EMOTICON:
+        this.push('emoticonData', ...data);
+        break;
+      default:
+        throw new Error(`Unknown category ${category}.`);
+    }
+
+    this.push('categoriesData', ...data);
+
+    // If all data is fetched, trigger search index.
+    if (lastPartition) {
+      this.searchLazyIndexing = false;
+    }
+  }
+
   onSearchChanged(newValue) {
     this.$['list-container'].style.display = newValue ? 'none' : '';
   }
@@ -768,7 +814,7 @@
     // There is quite a lot of emoji data to load which causes slow rendering.
     // Just load the first emoji category immediately, and defer loading of the
     // other categories (which will be off screen).
-    this.emojiData = [data[0]];
+    this.updateCategoryData([data[0]], CategoryEnum.EMOJI);
     afterNextRender(
         this,
         () => this.fetchOrderingData(`${this.emojiDataUrl}_remaining.json`)
@@ -776,7 +822,7 @@
   }
 
   onEmojiDataLoadedRemaining(data) {
-    this.push('emojiData', ...data);
+    this.updateCategoryData(data, CategoryEnum.EMOJI, !this.v2Enabled);
     this.dispatchEvent(events.createCustomEvent(
       events.EMOJI_REMAINING_DATA_LOADED));
     afterNextRender(this, () => {
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
index 187e744..082a8c6 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.html
@@ -176,9 +176,10 @@
     <div class="sr-only" role="heading" aria-level="1">
       Emoji Search Results
     </div>
-    <template is="dom-if" if="[[!v2Enabled]]">
-      <template is="dom-repeat" items="[[emojiResults]]">
-        <!-- TODO(b/234673508): Remove the emoji button -->
+    <!-- TODO(b/234673356): Merge this block into the V2 one. -->
+    <template is="dom-if"
+        if="[[shouldShowV1Results(searchResults, v2Enabled)]]">
+      <template is="dom-repeat" items="[[searchResults.0.emoji]]">
         <div class="result" tabindex="0" on-click="onResultClick">
           <emoji-button tabindex="-1"
               emoji="[[item.base.string]]"
@@ -190,16 +191,14 @@
     </template>
     <template is="dom-if" if="[[v2Enabled]]">
       <div id="search-results">
-        <emoji-group id="emoji-result" data="[[emojiResults]]"
-          category="emoji">
-        </emoji-group>
-        <emoji-group id="emoticon-result" data="[[emoticonResults]]"
-          category="emoticon">
-        </emoji-group>
+        <template is="dom-repeat" items="[[searchResults]]">
+          <emoji-group data="[[item.emoji]]" category$="[[item.category]]">
+          </emoji-group>
+        </template>
       </div>
     </template>
     <template is="dom-if"
-      if="[[isSearchResultEmpty(emojiResults, emoticonResults)]]">
+      if="[[!searchResults.length]]">
       <div class="no-result">
         <picture>
           <source srcset="no_results_dark.svg"
diff --git a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.js b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.js
index d5cfbc7..253e5394 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/emoji_search.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/emoji_search.js
@@ -8,12 +8,7 @@
 import {EmojiButton} from './emoji_button.js';
 import {EmojiCategoryButton} from './emoji_category_button.js';
 import Fuse from './fuse.js';
-import {CategoryEnum, EmojiGroupData, EmojiVariants} from './types.js';
-
-/**
- * @typedef {!Array<{item: !EmojiVariants}>} FuseResults
- */
-let FuseResults;
+import {EmojiGroupData, EmojiVariants, CategoryEnum} from './types.js';
 
 export class EmojiSearch extends PolymerElement {
   static get is() {
@@ -27,42 +22,37 @@
   static get properties() {
     return {
       /** @type {EmojiGroupData} */
-      emojiData: {type: Array, readonly: true},
-      /** @type {EmojiGroupData} */
-      emoticonData: {type: Array, readonly: true},
+      categoriesData: {type: Array, readonly: true},
       /** @type {!string} */
       search: {type: String, notify: true},
-      /** @private {!Array<!EmojiVariants>} */
-      emojiList: {
-        type: Array,
-        computed: 'computeEmojiList(emojiData,emojiData.length)',
-        observer: 'onEmojiListChanged'
-      },
-      /** @private {!Array<!EmojiVariants>} */
-      emoticonList: {
-        type: Array,
-        computed: 'computeEmojiList(emoticonData)',
-        observer: 'onEmoticonListChanged'
-      },
-      /** @private {!Array<!EmojiVariants>} */
-      emojiResults:
-          {type: Array, computed: 'computeSearchResults(search, \'emoji\')'},
-      /** @private {!Array<!EmojiVariants>} */
-      emoticonResults:
-          {type: Array, computed: 'computeSearchResults(search, \'emoticon\')'},
+      /** @type {!boolean} */
+      lazyIndexing: {type: Boolean, value: true},
+      /** @private {EmojiGroupData} */
+      searchResults: {type: Array, computed: 'computeSearchResults(search)'},
       /** @private {!boolean} */
       v2Enabled: {
         type: Boolean,
         value: false,
         reflectToAttribute: true,
         readonly: true
-      }
+      },
+      /** @private {!boolean} */
+      needIndexing: {type: Boolean, value: false},
     };
   }
 
+  static get observers() {
+    return [
+      'categoriesDataChanged(categoriesData.splices,lazyIndexing)'
+    ];
+  }
+
   constructor() {
     super();
-    const fuseConfig = {
+
+    // TODO(b/235419647): Update the config to use extended search.
+    /** @private {Object<string, Object>} */
+    this.fuseConfig = {
       threshold: 0.0,        // Exact match only.
       ignoreLocation: true,  // Match in all locations.
       keys: [
@@ -70,16 +60,14 @@
         'base.keywords',
       ]
     };
-    this.emojiFuse = new Fuse([], fuseConfig);
-    this.emoticonFuse = new Fuse([], fuseConfig);
-    this.addEventListener('scroll', () => {
-      this.onSearchScroll();
-    });
+    /** @private {Map<CategoryEnum,Object>} */
+    this.fuseInstances = new Map();
   }
 
   ready() {
     super.ready();
 
+    this.addEventListener('scroll', () => this.onSearchScroll());
     this.addEventListener('search', ev => this.onSearch(ev.detail));
     this.$.search.getSearchInput().addEventListener(
         'keydown',
@@ -93,6 +81,30 @@
   }
 
   /**
+   * Processes the changes to the data and determines whether indexing is
+   * needed or not. It also triggers indexing if mode is not lazy and there
+   * are new changes.
+   *
+   * @param {*} changedRecords
+   * @param {!boolean} lazyIndexing
+   * @returns
+   */
+  categoriesDataChanged(changedRecords, lazyIndexing) {
+    if (!changedRecords && lazyIndexing) {
+      return;
+    }
+
+    // Indexing is needed if there are new changes.
+    this.needIndexing = this.needIndexing || changedRecords.indexSplices
+        .some((s) => s.removed.length + s.addedCount > 0);
+
+    // Trigger indexing if mode is not lazy and indexing is needed.
+    if (!lazyIndexing && this.needIndexing) {
+      this.createSearchIndices();
+    }
+  }
+
+  /**
    * Event handler for keydown anywhere in the search component.
    * Used to move the focused result up/down on arrow presses.
    * @param {KeyboardEvent} ev
@@ -120,6 +132,7 @@
     ev.preventDefault();
     ev.stopPropagation();
 
+    // TODO(v/b/234673356): Move the navigation logic to emoji-group.
     if (!focusedResult) {
       return;
     }
@@ -146,9 +159,9 @@
    * @param {KeyboardEvent} ev
    */
   onSearchKeyDown(ev) {
+    const resultsCount = this.getNumSearchResults();
     // if not searching or no results, do nothing.
-    if (!this.search ||
-        (this.emojiResults.length === 0 && this.emoticonResults.length === 0)) {
+    if (!this.search || resultsCount === 0) {
       return;
     }
 
@@ -159,19 +172,17 @@
       ev.preventDefault();
       ev.stopPropagation();
 
+      // TODO(b/234673356): Remove this block.
       if (!this.v2Enabled) {
         // focus first item in result list.
         const firstButton = this.shadowRoot.querySelector('.result');
         firstButton.focus();
 
         // if there is only one result, select it on enter.
-        if (isEnter && this.emojiResults.length === 1) {
+        if (isEnter && resultsCount === 1) {
           firstButton.querySelector('emoji-button').click();
         }
       } else {
-        const resultsCount =
-          this.emojiResults.length + this.emoticonResults.length;
-
         if (resultsCount === 0) {
           return;
         }
@@ -196,11 +207,10 @@
    * 1) Remove duplicates.
    * 2) Remove groupings.
    * @param {!EmojiGroupData} emojiData
-   * @param {number} emojiDataLength Used to trick polymer into calling this
-   *     when the emojidata is updated via push
    * @return {!Array<!EmojiVariants>}
    */
-  computeEmojiList(emojiData, emojiDataLength) {
+  preprocessDataForIndexing(emojiData) {
+    // TODO(b/235419647): Remove addition of extra space.
     return Array.from(
         new Map(emojiData.map(group => group.emoji).flat(1).map(emoji => {
           // The Fuse search library in ChromeOS doesn't support prefix
@@ -217,6 +227,39 @@
         })).values());
   }
 
+  /**
+   * Indexes category data for search.
+   *
+   * Note: The indexing is done for all data from scratch, it is possible
+   * to index only the new changes with the cost of increasing logic
+   * complexity.
+   */
+  createSearchIndices() {
+    if (!this.categoriesData || this.categoriesData.length === 0) {
+      return;
+    }
+
+    // Get the list of unique categories in the order they appeared
+    // in the data.
+    const categories = [...new Set(
+      this.categoriesData.map(item => item.category))];
+
+    // Remove existing indices.
+    this.fuseInstances.clear();
+
+    for (const category of categories) {
+      // Filter records for the category and preprocess them.
+      const indexableEmojis = this.preprocessDataForIndexing(
+          this.categoriesData.filter(
+            emojiGroup => emojiGroup.category === category));
+
+      // Create a new index for the category.
+      this.fuseInstances.set(category,
+          new Fuse(indexableEmojis, this.fuseConfig));
+    }
+    this.needIndexing = false;
+  }
+
   onSearchScroll() {
     if (!this.v2Enabled) {
       this.$['search-shadow'].style.boxShadow =
@@ -227,50 +270,44 @@
   }
 
   /**
+   * Computes search results for a keyword.
    *
-   * @param {!Array<!EmojiVariants>} emojiList
-   * @suppress {missingProperties}
+   * @param {?string} search Search keyword
+   * @returns {EmojiGroupData} Search results for all categories that had
+   *    matching items.
    */
-  onEmojiListChanged(emojiList) {
-    // suppressed property error due to Fuse being untyped.
-    this.emojiFuse.setCollection(emojiList);
-  }
-
-  /**
-   *
-   * @param {!Array<!EmojiVariants>} emoticonList
-   * @suppress {missingProperties}
-   */
-  onEmoticonListChanged(emoticonList) {
-    this.emoticonFuse.setCollection(emoticonList);
-  }
-
-  /**
-   * @param {?string} search
-   * @param {CategoryEnum} category
-   */
-  computeSearchResults(search, category) {
+  computeSearchResults(search) {
     if (!search) {
       return [];
     }
+
+    // Index data if needed (for lazy mode).
+    if (this.needIndexing) {
+      this.createSearchIndices();
+    }
+
+    // TODO(b/235419647): Use `^${search}|'" ${search}"'` for extended search.
     // Add an initial space to force prefix matching only.
     const prefixSearchTerm = ` ${search}`;
-    let fuseResults = [];
-    if (!this.v2Enabled) {
-      fuseResults = this.emojiFuse.search(prefixSearchTerm);
-    } else {
-      switch (category) {
-        case CategoryEnum.EMOJI:
-          fuseResults = this.emojiFuse.search(prefixSearchTerm);
-          break;
-        case CategoryEnum.EMOTICON:
-          fuseResults = this.emoticonFuse.search(prefixSearchTerm);
-          break;
-        default:
-          throw new Error('Unknown category.');
+
+    const searchResults = [];
+
+    // Search the keyword in the fuse instance of each category.
+    for (const [category, fuseInstance] of this.fuseInstances.entries()) {
+      const categorySearchResult = (/** @type {Object} */ (fuseInstance))
+        .search(prefixSearchTerm).map(item => item.item);
+
+      // Add the category results if not empty.
+      if (categorySearchResult.length !== 0) {
+        searchResults.push({
+          'category': category,
+          'group': '',
+          'emoji': categorySearchResult,
+        });
       }
     }
-    return fuseResults.map(item => item.item);
+
+    return searchResults;
   }
 
   onResultClick(ev) {
@@ -284,7 +321,7 @@
   }
 
   /**
-   * Find the first button in the search result page.
+   * Finds the first button in the search result page.
    *
    * @returns {?HTMLElement} First button or null for no results.
    */
@@ -301,15 +338,25 @@
   }
 
   /**
-   * @param {!Array<!EmojiVariants>} emojiResults
-   * @param {!Array<!EmojiVariants>} emoticonResults
-   * @returns {boolean}
+   * Determines visibility of the search results for V1.
+   *
+   * @param {!EmojiGroupData} searchResults Search results.
+   * @param {!boolean} v2Enabled V2 enablement status.
+   * @returns {boolean} True if V2 is not enabled and there are results items.
    */
-  isSearchResultEmpty(emojiResults, emoticonResults) {
-    if (!this.v2Enabled) {
-      return emojiResults.length === 0;
-    }
-    return emojiResults.length === 0 && emoticonResults.length === 0;
+  shouldShowV1Results(searchResults, v2Enabled) {
+    // TODO(b/234673356): Remove this function.
+    return !v2Enabled && searchResults.length > 0;
+  }
+
+  /**
+   * Calculates the total number of items in the search results.
+   *
+   * @returns {number} Number of search results.
+   */
+  getNumSearchResults() {
+    return this.searchResults.reduce(
+      (acc, item) => acc + item.emoji.length, 0);
   }
 }
 
diff --git a/chrome/browser/resources/chromeos/emoji_picker/types.js b/chrome/browser/resources/chromeos/emoji_picker/types.js
index fde0e39..0f73665 100644
--- a/chrome/browser/resources/chromeos/emoji_picker/types.js
+++ b/chrome/browser/resources/chromeos/emoji_picker/types.js
@@ -18,7 +18,8 @@
 export let EmojiVariants;
 
 /**
- * @typedef {{group: string, emoji: !Array<EmojiVariants>}} EmojiGroup
+ * @typedef {{category: CategoryEnum, group: string,
+ *            emoji: !Array<EmojiVariants>}} EmojiGroup
  */
 export let EmojiGroup;
 
diff --git a/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn b/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
index bbc66cfc..df70a76 100644
--- a/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
+++ b/chrome/browser/resources/chromeos/launcher_internals/BUILD.gn
@@ -46,7 +46,8 @@
   deps = [ ":build_ts" ]
   input_files = [ "index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 
   grd_prefix = "launcher_internals"
   out_grd = resources_grd_file
diff --git a/chrome/browser/resources/commander/BUILD.gn b/chrome/browser/resources/commander/BUILD.gn
index 473ed029..6e4e65e 100644
--- a/chrome/browser/resources/commander/BUILD.gn
+++ b/chrome/browser/resources/commander/BUILD.gn
@@ -12,16 +12,6 @@
 
 preprocess_folder = "preprocessed"
 
-generate_grd("build_grd") {
-  grd_prefix = "commander"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [ "commander.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -70,3 +60,14 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "commander"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [ "commander.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/connectors_internals/BUILD.gn b/chrome/browser/resources/connectors_internals/BUILD.gn
index 431f457..b9da289 100644
--- a/chrome/browser/resources/connectors_internals/BUILD.gn
+++ b/chrome/browser/resources/connectors_internals/BUILD.gn
@@ -65,7 +65,8 @@
   deps = [ ":build_ts" ]
   input_files = [ "index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 
   grd_prefix = "connectors_internals"
   out_grd = resources_grd_file
diff --git a/chrome/browser/resources/discards/BUILD.gn b/chrome/browser/resources/discards/BUILD.gn
index b754571..bca8b56 100644
--- a/chrome/browser/resources/discards/BUILD.gn
+++ b/chrome/browser/resources/discards/BUILD.gn
@@ -134,7 +134,8 @@
     ":build_graph_tab_grdp",
     ":build_ts",
   ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   grdp_files = [ "$target_gen_dir/discards_graph_tab.grdp" ]
   grd_prefix = "discards"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
diff --git a/chrome/browser/resources/downloads/BUILD.gn b/chrome/browser/resources/downloads/BUILD.gn
index 8fce650..1d56135 100644
--- a/chrome/browser/resources/downloads/BUILD.gn
+++ b/chrome/browser/resources/downloads/BUILD.gn
@@ -36,25 +36,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  input_files = [
-    "downloads.html",
-    "images/incognito_marker.svg",
-    "images/no_downloads.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [ "downloads.rollup.js|downloads.js" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-  grd_prefix = "downloads"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -111,3 +92,23 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  input_files = [
+    "downloads.html",
+    "images/incognito_marker.svg",
+    "images/no_downloads.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [ "downloads.rollup.js|downloads.js" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+  grd_prefix = "downloads"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
diff --git a/chrome/browser/resources/extensions/BUILD.gn b/chrome/browser/resources/extensions/BUILD.gn
index a700ab321..b5ddcf8 100644
--- a/chrome/browser/resources/extensions/BUILD.gn
+++ b/chrome/browser/resources/extensions/BUILD.gn
@@ -36,22 +36,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "extensions"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [ "extensions.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    resource_path_rewrites = [ "extensions.rollup.js|extensions.js" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -121,3 +105,20 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "extensions"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [ "extensions.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    resource_path_rewrites = [ "extensions.rollup.js|extensions.js" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/feed/BUILD.gn b/chrome/browser/resources/feed/BUILD.gn
index 379840d..233cbd4 100644
--- a/chrome/browser/resources/feed/BUILD.gn
+++ b/chrome/browser/resources/feed/BUILD.gn
@@ -43,15 +43,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "feed"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  input_files = [ "feed.html" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 ts_library("build_ts") {
   root_dir = "$target_gen_dir/$preprocess_folder"
   out_dir = "$target_gen_dir/tsc"
@@ -66,3 +57,13 @@
     ":preprocess",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "feed"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  input_files = [ "feed.html" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/chrome/browser/resources/feedback_webui/js/BUILD.gn b/chrome/browser/resources/feedback_webui/js/BUILD.gn
index 92aec99..21c09853 100644
--- a/chrome/browser/resources/feedback_webui/js/BUILD.gn
+++ b/chrome/browser/resources/feedback_webui/js/BUILD.gn
@@ -41,7 +41,8 @@
 generate_grd("build_grdp") {
   grd_prefix = "feedback_webui_js"
   out_grd = "$target_gen_dir/resources.grdp"
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "js"
   deps = [ ":build_ts" ]
 }
diff --git a/chrome/browser/resources/history/BUILD.gn b/chrome/browser/resources/history/BUILD.gn
index c3a52c3..af87f665 100644
--- a/chrome/browser/resources/history/BUILD.gn
+++ b/chrome/browser/resources/history/BUILD.gn
@@ -42,31 +42,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "history"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "history.html",
-    "images/journeys.svg",
-    "images/list.svg",
-    "images/sign_in_promo_dark.svg",
-    "images/sign_in_promo.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [
-      "history.rollup.js|history.js",
-      "lazy_load.rollup.js|lazy_load.js",
-    ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -128,3 +103,29 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "history"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "history.html",
+    "images/journeys.svg",
+    "images/list.svg",
+    "images/sign_in_promo_dark.svg",
+    "images/sign_in_promo.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [
+      "history.rollup.js|history.js",
+      "lazy_load.rollup.js|lazy_load.js",
+    ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/identity_internals/BUILD.gn b/chrome/browser/resources/identity_internals/BUILD.gn
index 2958067..d1aa5aa 100644
--- a/chrome/browser/resources/identity_internals/BUILD.gn
+++ b/chrome/browser/resources/identity_internals/BUILD.gn
@@ -41,7 +41,8 @@
     "identity_internals.html",
   ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   deps = [ ":build_ts" ]
 }
 
diff --git a/chrome/browser/resources/internals/user_education/BUILD.gn b/chrome/browser/resources/internals/user_education/BUILD.gn
index 0989713a..72e6873 100644
--- a/chrome/browser/resources/internals/user_education/BUILD.gn
+++ b/chrome/browser/resources/internals/user_education/BUILD.gn
@@ -35,16 +35,6 @@
   outputs = [ "$preprocess_folder/{{source_file_part}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "user_education_internals"
-  out_grd = "$target_gen_dir/resources.grdp"
-  input_files = [ "index.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  deps = [ ":build_ts" ]
-  resource_path_prefix = "user-education"
-}
-
 ts_library("build_ts") {
   root_dir = preprocess_folder
   out_dir = "$target_gen_dir/tsc"
@@ -61,3 +51,14 @@
     ":preprocess_src",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "user_education_internals"
+  out_grd = "$target_gen_dir/resources.grdp"
+  input_files = [ "index.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  deps = [ ":build_ts" ]
+  resource_path_prefix = "user-education"
+}
diff --git a/chrome/browser/resources/management/BUILD.gn b/chrome/browser/resources/management/BUILD.gn
index b089c1b8..6f968981 100644
--- a/chrome/browser/resources/management/BUILD.gn
+++ b/chrome/browser/resources/management/BUILD.gn
@@ -31,15 +31,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "management"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [ "management.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -70,3 +61,13 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "management"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [ "management.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/media/BUILD.gn b/chrome/browser/resources/media/BUILD.gn
index 772cb4d..145ae7a 100644
--- a/chrome/browser/resources/media/BUILD.gn
+++ b/chrome/browser/resources/media/BUILD.gn
@@ -66,7 +66,8 @@
     "webrtc_logs.html",
   ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   deps = [ ":build_ts" ]
 }
 
diff --git a/chrome/browser/resources/media_router/cast_feedback/BUILD.gn b/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
index 7e1231c..c923a88 100644
--- a/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
+++ b/chrome/browser/resources/media_router/cast_feedback/BUILD.gn
@@ -32,17 +32,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-# Build a .grd file from the various resource files needed by the
-# feedback dialog.
-generate_grd("build_grd") {
-  input_files = [ "feedback.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  grd_prefix = "media_router_feedback"
-  out_grd = "$target_gen_dir/resources.grd"
-}
-
 preprocess_if_expr("preprocess_gen") {
   deps = [ ":html_wrapper_files" ]
   in_folder = target_gen_dir
@@ -78,3 +67,15 @@
     ":preprocess_src",
   ]
 }
+
+# Build a .grd file from the various resource files needed by the
+# feedback dialog.
+generate_grd("build_grd") {
+  input_files = [ "feedback.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  grd_prefix = "media_router_feedback"
+  out_grd = "$target_gen_dir/resources.grd"
+}
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index 9c54fdf..1e0d80b 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -84,56 +84,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = grd_prefix
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "new_tab_page.html",
-    "shared_vars.css",
-    "modules/chromefetti.svg",
-    "untrusted/background_image.html",
-    "untrusted/background_image.js",
-    "untrusted/image.html",
-    "untrusted/one_google_bar.html",
-    "untrusted/one_google_bar.js",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  grdp_files = [
-    "$target_gen_dir/icons/resources.grdp",
-    "$target_gen_dir/modules/cart/icons/resources.grdp",
-    "$target_gen_dir/modules/photos/icons/resources.grdp",
-    "$target_gen_dir/modules/photos/images/resources.grdp",
-    "$target_gen_dir/modules/recipes_v2/icons/resources.grdp",
-    "$target_gen_dir/realbox/icons/resources.grdp",
-  ]
-
-  deps = [
-    "icons:build_grdp",
-    "modules/cart/icons:build_grdp",
-    "modules/photos/icons:build_grdp",
-    "modules/photos/images:build_grdp",
-    "modules/recipes_v2/icons:build_grdp",
-    "realbox/icons:build_grdp",
-  ]
-
-  if (optimize_webui) {
-    deps += [
-      ":build_mojo_grdp",
-      ":optimized_js",
-    ]
-    resource_path_rewrites = [
-      "new_tab_page.rollup.js|new_tab_page.js",
-      "lazy_load.rollup.js|lazy_load.js",
-    ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    grdp_files += [ "$target_gen_dir/mojo_resources.grdp" ]
-  } else {
-    deps += [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 grit("resources") {
   defines = chrome_grit_defines + [ "is_official_build=$is_official_build" ]
 
@@ -235,3 +185,54 @@
     ]
   }
 }
+
+generate_grd("build_grd") {
+  grd_prefix = grd_prefix
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "new_tab_page.html",
+    "shared_vars.css",
+    "modules/chromefetti.svg",
+    "untrusted/background_image.html",
+    "untrusted/background_image.js",
+    "untrusted/image.html",
+    "untrusted/one_google_bar.html",
+    "untrusted/one_google_bar.js",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  grdp_files = [
+    "$target_gen_dir/icons/resources.grdp",
+    "$target_gen_dir/modules/cart/icons/resources.grdp",
+    "$target_gen_dir/modules/photos/icons/resources.grdp",
+    "$target_gen_dir/modules/photos/images/resources.grdp",
+    "$target_gen_dir/modules/recipes_v2/icons/resources.grdp",
+    "$target_gen_dir/realbox/icons/resources.grdp",
+  ]
+
+  deps = [
+    "icons:build_grdp",
+    "modules/cart/icons:build_grdp",
+    "modules/photos/icons:build_grdp",
+    "modules/photos/images:build_grdp",
+    "modules/recipes_v2/icons:build_grdp",
+    "realbox/icons:build_grdp",
+  ]
+
+  if (optimize_webui) {
+    deps += [
+      ":build_mojo_grdp",
+      ":optimized_js",
+    ]
+    resource_path_rewrites = [
+      "new_tab_page.rollup.js|new_tab_page.js",
+      "lazy_load.rollup.js|lazy_load.js",
+    ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    grdp_files += [ "$target_gen_dir/mojo_resources.grdp" ]
+  } else {
+    deps += [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/new_tab_page_instant/BUILD.gn b/chrome/browser/resources/new_tab_page_instant/BUILD.gn
index cf47c03e..03078cf 100644
--- a/chrome/browser/resources/new_tab_page_instant/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page_instant/BUILD.gn
@@ -9,19 +9,6 @@
 
 assert(is_linux || is_chromeos || is_win || is_mac || is_fuchsia)
 
-generate_grd("build_grd") {
-  grd_prefix = "new_tab_page_instant"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "most_visited_title.css",
-    "most_visited_title.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 grit("resources") {
   defines = chrome_grit_defines + [ "is_official_build=$is_official_build" ]
   enable_input_discovery_for_gn_analyze = false
@@ -42,3 +29,17 @@
   in_files = [ "most_visited_title.ts" ]
   definitions = [ "embedded_search.d.ts" ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "new_tab_page_instant"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "most_visited_title.css",
+    "most_visited_title.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/new_tab_page_third_party/BUILD.gn b/chrome/browser/resources/new_tab_page_third_party/BUILD.gn
index 81604eb..47cec11 100644
--- a/chrome/browser/resources/new_tab_page_third_party/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page_third_party/BUILD.gn
@@ -25,15 +25,6 @@
   outputs = [ "$target_gen_dir/$preprocess_folder/{{source_file_part}}" ]
 }
 
-generate_grd("build_grd") {
-  grd_prefix = grd_prefix
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [ "new_tab_page_third_party.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 grit("resources") {
   defines = chrome_grit_defines
   enable_input_discovery_for_gn_analyze = false
@@ -68,3 +59,13 @@
     ":preprocess",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = grd_prefix
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [ "new_tab_page_third_party.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/ntp4/BUILD.gn b/chrome/browser/resources/ntp4/BUILD.gn
index f822e03..072bcec 100644
--- a/chrome/browser/resources/ntp4/BUILD.gn
+++ b/chrome/browser/resources/ntp4/BUILD.gn
@@ -26,25 +26,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_apps_grd") {
-  grd_prefix = "apps"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "apps_page.css",
-    "images/error_yellow900.svg",
-    "images/trash.png",
-    "nav_dot.css",
-    "new_tab.css",
-    "new_tab.html",
-    "tile_page.css",
-    "trash.css",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 # Note: There are no plans to migrate this page to TypeScript, as it is a fairly
 # old page with an undecided future, and would be a lot of work. Passing JS file
 # through TS compiler to get some basic static checks (mostly validating syntax
@@ -69,3 +50,23 @@
   definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
   deps = [ "//ui/webui/resources:library" ]
 }
+
+generate_grd("build_apps_grd") {
+  grd_prefix = "apps"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "apps_page.css",
+    "images/error_yellow900.svg",
+    "images/trash.png",
+    "nav_dot.css",
+    "new_tab.css",
+    "new_tab.html",
+    "tile_page.css",
+    "trash.css",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index a57e58a..e653b8a8 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -51,32 +51,6 @@
   ]
 }
 
-# Build the grdp for Print Preview.
-generate_grd("build_print_preview_grdp") {
-  # Get all the shared files out of the tsc folder.
-  input_files = print_preview_grdp_input_files
-  input_files_base_dir =
-      rebase_path("$target_gen_dir/$tsc_folder", root_build_dir)
-
-  manifest_files = [ "$target_gen_dir/$print_preview_html_css_manifest" ]
-  deps = [
-    ":build_ts",
-    ":preprocess_print_preview_html_css",
-  ]
-  resource_path_rewrites = [
-    "index_pp.html|index.html",
-
-    # Expose pdf_viewer_pp.js as pdf_viewer_wrapper.js so that the PDF viewer
-    # and Print Preview viewer can use the same main.js source.
-    "pdf_viewer_pp.js|pdf_viewer_wrapper.js",
-  ]
-  grd_prefix = "print_preview_pdf"
-
-  # Print Preview expects to import from "pdf/" relative path
-  resource_path_prefix = "pdf"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grdp"
-}
-
 if (optimize_webui) {
   build_manifest = "build_manifest.json"
 
@@ -144,38 +118,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  input_files = [
-    "index.css",
-    "index.html",
-  ]
-  if (enable_ink) {
-    input_files += [ "ink/index.html" ]
-  }
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [
-      ":build",
-      ":build_excluded_grdp",
-    ]
-    resource_path_rewrites =
-        [ "pdf_viewer_wrapper.rollup.js|pdf_viewer_wrapper.js" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    grdp_files = [ "$target_gen_dir/excluded_resources.grdp" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-
-  deps += [ ":build_internal_plugin" ]
-  manifest_files += [ "$target_gen_dir/$build_internal_plugin_manifest" ]
-
-  grd_prefix = "pdf"
-  out_grd = "$target_gen_dir/resources.grd"
-  resource_path_prefix = "pdf"
-}
-
 grit("resources") {
   defines = chrome_grit_defines + [ "enable_ink=$enable_ink" ]
 
@@ -218,3 +160,62 @@
     ":preprocess_generated",
   ]
 }
+
+# Build the grdp for Print Preview.
+generate_grd("build_print_preview_grdp") {
+  # Get all the shared files out of the tsc folder.
+  input_files = print_preview_grdp_input_files
+  input_files_base_dir =
+      rebase_path("$target_gen_dir/$tsc_folder", root_build_dir)
+
+  manifest_files = [ "$target_gen_dir/$print_preview_html_css_manifest" ]
+  deps = [
+    ":build_ts",
+    ":preprocess_print_preview_html_css",
+  ]
+  resource_path_rewrites = [
+    "index_pp.html|index.html",
+
+    # Expose pdf_viewer_pp.js as pdf_viewer_wrapper.js so that the PDF viewer
+    # and Print Preview viewer can use the same main.js source.
+    "pdf_viewer_pp.js|pdf_viewer_wrapper.js",
+  ]
+  grd_prefix = "print_preview_pdf"
+
+  # Print Preview expects to import from "pdf/" relative path
+  resource_path_prefix = "pdf"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grdp"
+}
+
+generate_grd("build_grd") {
+  input_files = [
+    "index.css",
+    "index.html",
+  ]
+  if (enable_ink) {
+    input_files += [ "ink/index.html" ]
+  }
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [
+      ":build",
+      ":build_excluded_grdp",
+    ]
+    resource_path_rewrites =
+        [ "pdf_viewer_wrapper.rollup.js|pdf_viewer_wrapper.js" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    grdp_files = [ "$target_gen_dir/excluded_resources.grdp" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+
+  deps += [ ":build_internal_plugin" ]
+  manifest_files += [ "$target_gen_dir/$build_internal_plugin_manifest" ]
+
+  grd_prefix = "pdf"
+  out_grd = "$target_gen_dir/resources.grd"
+  resource_path_prefix = "pdf"
+}
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index adcec0a..9df77c9 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -39,23 +39,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  input_files = [ "print_preview.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ "../pdf:build_print_preview_grdp" ]
-  grdp_files = [ "$root_gen_dir/chrome/browser/resources/pdf/print_preview_pdf_resources.grdp" ]
-  if (optimize_webui) {
-    deps += [ ":build" ]
-    resource_path_rewrites = [ "print_preview.rollup.js|print_preview.js" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-  } else {
-    deps += [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-  grd_prefix = "print_preview"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-}
-
 css_to_wrapper("css_wrapper_files") {
   in_files = css_files
 }
@@ -124,3 +107,21 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  input_files = [ "print_preview.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ "../pdf:build_print_preview_grdp" ]
+  grdp_files = [ "$root_gen_dir/chrome/browser/resources/pdf/print_preview_pdf_resources.grdp" ]
+  if (optimize_webui) {
+    deps += [ ":build" ]
+    resource_path_rewrites = [ "print_preview.rollup.js|print_preview.js" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+  } else {
+    deps += [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+  grd_prefix = "print_preview"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
diff --git a/chrome/browser/resources/privacy_sandbox/BUILD.gn b/chrome/browser/resources/privacy_sandbox/BUILD.gn
index 9cdb866..7da179964 100644
--- a/chrome/browser/resources/privacy_sandbox/BUILD.gn
+++ b/chrome/browser/resources/privacy_sandbox/BUILD.gn
@@ -31,19 +31,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "privacy_sandbox"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "privacy_sandbox_dialog.html",
-    "images/privacy_sandbox_confirmation_banner.svg",
-    "images/privacy_sandbox_confirmation_banner_dark.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -76,3 +63,17 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "privacy_sandbox"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "privacy_sandbox_dialog.html",
+    "images/privacy_sandbox_confirmation_banner.svg",
+    "images/privacy_sandbox_confirmation_banner_dark.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/profile_internals/BUILD.gn b/chrome/browser/resources/profile_internals/BUILD.gn
index a92d8f0..d9f959f 100644
--- a/chrome/browser/resources/profile_internals/BUILD.gn
+++ b/chrome/browser/resources/profile_internals/BUILD.gn
@@ -14,15 +14,6 @@
 # Move everything to one folder using preprocess_if_expr.
 preprocess_folder = "preprocessed"
 
-generate_grd("build_grd") {
-  grd_prefix = "profile_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [ "profile_internals.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = [
@@ -74,3 +65,13 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "profile_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [ "profile_internals.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/segmentation_internals/BUILD.gn b/chrome/browser/resources/segmentation_internals/BUILD.gn
index 22eb8a9..eb13123 100644
--- a/chrome/browser/resources/segmentation_internals/BUILD.gn
+++ b/chrome/browser/resources/segmentation_internals/BUILD.gn
@@ -26,15 +26,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "segmentation_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [ "segmentation_internals.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 copy("copy_ts") {
   sources = [
     "segmentation_internals.ts",
@@ -67,3 +58,13 @@
     ":copy_ts",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "segmentation_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [ "segmentation_internals.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/chrome/browser/resources/settings/BUILD.gn b/chrome/browser/resources/settings/BUILD.gn
index 54391a5..5e9e479 100644
--- a/chrome/browser/resources/settings/BUILD.gn
+++ b/chrome/browser/resources/settings/BUILD.gn
@@ -60,93 +60,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "settings"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "images/cookies_banner_dark.svg",
-    "images/cookies_banner.svg",
-    "images/googleg_standard_clr_32px.svg",
-    "images/password_check_neutral_dark.svg",
-    "images/password_check_neutral.svg",
-    "images/password_check_positive_dark.svg",
-    "images/password_check_positive.svg",
-    "images/permissions_banner_dark.svg",
-    "images/permissions_banner.svg",
-    "images/privacy_guide/clear_on_exit_graphic_dark_v2.svg",
-    "images/privacy_guide/clear_on_exit_graphic_dark.svg",
-    "images/privacy_guide/clear_on_exit_graphic_v2.svg",
-    "images/privacy_guide/clear_on_exit_graphic.svg",
-    "images/privacy_guide/clouds_graphic_dark.svg",
-    "images/privacy_guide/clouds_graphic.svg",
-    "images/privacy_guide/completion_banner_circle.svg",
-    "images/privacy_guide/completion_banner_dark_v2.svg",
-    "images/privacy_guide/completion_banner_dark.svg",
-    "images/privacy_guide/completion_banner_pill.svg",
-    "images/privacy_guide/completion_banner_square.svg",
-    "images/privacy_guide/completion_banner_triangle.svg",
-    "images/privacy_guide/completion_banner_v2.svg",
-    "images/privacy_guide/completion_banner.svg",
-    "images/privacy_guide/cookies_graphic_dark_v2.svg",
-    "images/privacy_guide/cookies_graphic_dark.svg",
-    "images/privacy_guide/cookies_graphic_v2.svg",
-    "images/privacy_guide/cookies_graphic.svg",
-    "images/privacy_guide/hills_graphic_dark.svg",
-    "images/privacy_guide/hills_graphic.svg",
-    "images/privacy_guide/history_sync_graphic_dark_v2.svg",
-    "images/privacy_guide/history_sync_graphic_dark.svg",
-    "images/privacy_guide/history_sync_graphic_v2.svg",
-    "images/privacy_guide/history_sync_graphic.svg",
-    "images/privacy_guide/horizon_graphic_dark.svg",
-    "images/privacy_guide/horizon_graphic.svg",
-    "images/privacy_guide/msbb_graphic_dark_v2.svg",
-    "images/privacy_guide/msbb_graphic_dark.svg",
-    "images/privacy_guide/msbb_graphic_v2.svg",
-    "images/privacy_guide/msbb_graphic.svg",
-    "images/privacy_guide/privacy_sandbox_graphic_dark.svg",
-    "images/privacy_guide/privacy_sandbox_graphic.svg",
-    "images/privacy_guide/promo_banner_dark.svg",
-    "images/privacy_guide/promo_banner.svg",
-    "images/privacy_guide/safe_browsing_graphic_dark_v2.svg",
-    "images/privacy_guide/safe_browsing_graphic_dark.svg",
-    "images/privacy_guide/safe_browsing_graphic_v2.svg",
-    "images/privacy_guide/safe_browsing_graphic.svg",
-    "images/privacy_guide/waa_graphic_dark.svg",
-    "images/privacy_guide/waa_graphic.svg",
-    "images/privacy_guide/welcome_banner_dark.svg",
-    "images/privacy_guide/welcome_banner.svg",
-    "images/privacy_sandbox_banner_dark.svg",
-    "images/privacy_sandbox_banner.svg",
-    "images/privacy_sandbox_banner_v3_dark.svg",
-    "images/privacy_sandbox_banner_v3.svg",
-    "images/privacy_sandbox_floc_banner_dark.svg",
-    "images/privacy_sandbox_floc_banner.svg",
-    "images/safe_browsing_banner_dark.svg",
-    "images/safe_browsing_banner.svg",
-    "images/sync_banner_dark.svg",
-    "images/sync_banner.svg",
-    "privacy_sandbox/privacy_sandbox.html",
-    "settings.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [
-      ":build",
-      "privacy_sandbox:build_grdp",
-    ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [
-      "settings.rollup.js|settings.js",
-      "lazy_load.rollup.js|lazy_load.js",
-    ]
-    grdp_files = [ "$target_gen_dir/privacy_sandbox/resources.grdp" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 preprocess_if_expr("preprocess") {
   defines = chrome_grit_defines
   out_folder = "$target_gen_dir/$preprocess_folder"
@@ -308,3 +221,91 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "settings"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "images/cookies_banner_dark.svg",
+    "images/cookies_banner.svg",
+    "images/googleg_standard_clr_32px.svg",
+    "images/password_check_neutral_dark.svg",
+    "images/password_check_neutral.svg",
+    "images/password_check_positive_dark.svg",
+    "images/password_check_positive.svg",
+    "images/permissions_banner_dark.svg",
+    "images/permissions_banner.svg",
+    "images/privacy_guide/clear_on_exit_graphic_dark_v2.svg",
+    "images/privacy_guide/clear_on_exit_graphic_dark.svg",
+    "images/privacy_guide/clear_on_exit_graphic_v2.svg",
+    "images/privacy_guide/clear_on_exit_graphic.svg",
+    "images/privacy_guide/clouds_graphic_dark.svg",
+    "images/privacy_guide/clouds_graphic.svg",
+    "images/privacy_guide/completion_banner_circle.svg",
+    "images/privacy_guide/completion_banner_dark_v2.svg",
+    "images/privacy_guide/completion_banner_dark.svg",
+    "images/privacy_guide/completion_banner_pill.svg",
+    "images/privacy_guide/completion_banner_square.svg",
+    "images/privacy_guide/completion_banner_triangle.svg",
+    "images/privacy_guide/completion_banner_v2.svg",
+    "images/privacy_guide/completion_banner.svg",
+    "images/privacy_guide/cookies_graphic_dark_v2.svg",
+    "images/privacy_guide/cookies_graphic_dark.svg",
+    "images/privacy_guide/cookies_graphic_v2.svg",
+    "images/privacy_guide/cookies_graphic.svg",
+    "images/privacy_guide/hills_graphic_dark.svg",
+    "images/privacy_guide/hills_graphic.svg",
+    "images/privacy_guide/history_sync_graphic_dark_v2.svg",
+    "images/privacy_guide/history_sync_graphic_dark.svg",
+    "images/privacy_guide/history_sync_graphic_v2.svg",
+    "images/privacy_guide/history_sync_graphic.svg",
+    "images/privacy_guide/horizon_graphic_dark.svg",
+    "images/privacy_guide/horizon_graphic.svg",
+    "images/privacy_guide/msbb_graphic_dark_v2.svg",
+    "images/privacy_guide/msbb_graphic_dark.svg",
+    "images/privacy_guide/msbb_graphic_v2.svg",
+    "images/privacy_guide/msbb_graphic.svg",
+    "images/privacy_guide/privacy_sandbox_graphic_dark.svg",
+    "images/privacy_guide/privacy_sandbox_graphic.svg",
+    "images/privacy_guide/promo_banner_dark.svg",
+    "images/privacy_guide/promo_banner.svg",
+    "images/privacy_guide/safe_browsing_graphic_dark_v2.svg",
+    "images/privacy_guide/safe_browsing_graphic_dark.svg",
+    "images/privacy_guide/safe_browsing_graphic_v2.svg",
+    "images/privacy_guide/safe_browsing_graphic.svg",
+    "images/privacy_guide/waa_graphic_dark.svg",
+    "images/privacy_guide/waa_graphic.svg",
+    "images/privacy_guide/welcome_banner_dark.svg",
+    "images/privacy_guide/welcome_banner.svg",
+    "images/privacy_sandbox_banner_dark.svg",
+    "images/privacy_sandbox_banner.svg",
+    "images/privacy_sandbox_banner_v3_dark.svg",
+    "images/privacy_sandbox_banner_v3.svg",
+    "images/privacy_sandbox_floc_banner_dark.svg",
+    "images/privacy_sandbox_floc_banner.svg",
+    "images/safe_browsing_banner_dark.svg",
+    "images/safe_browsing_banner.svg",
+    "images/sync_banner_dark.svg",
+    "images/sync_banner.svg",
+    "privacy_sandbox/privacy_sandbox.html",
+    "settings.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [
+      ":build",
+      "privacy_sandbox:build_grdp",
+    ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [
+      "settings.rollup.js|settings.js",
+      "lazy_load.rollup.js|lazy_load.js",
+    ]
+    grdp_files = [ "$target_gen_dir/privacy_sandbox/resources.grdp" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.html b/chrome/browser/resources/settings/privacy_sandbox/app.html
index a80635f..2cfca050b 100644
--- a/chrome/browser/resources/settings/privacy_sandbox/app.html
+++ b/chrome/browser/resources/settings/privacy_sandbox/app.html
@@ -509,9 +509,8 @@
             src="./images/privacy_sandbox_floc_banner.svg">
       </picture>
       <settings-toggle-button id="flocToggleButton"
-          pref="{{prefs.generated.floc_enabled}}"
-          label="$i18n{privacySandboxPageFlocHeading}"
-          on-change="onFlocToggleButtonChange_">
+          pref="[[prefFlocToggle_]]"
+          label="$i18n{privacySandboxPageFlocHeading}">
       </settings-toggle-button>
       <div id="flocExplanation" class="cr-row continuation">
         <div class="secondary">$i18nRaw{privacySandboxPageFlocExplanation}</div>
diff --git a/chrome/browser/resources/settings/privacy_sandbox/app.ts b/chrome/browser/resources/settings/privacy_sandbox/app.ts
index 907cf8e8..d7eba5f7 100644
--- a/chrome/browser/resources/settings/privacy_sandbox/app.ts
+++ b/chrome/browser/resources/settings/privacy_sandbox/app.ts
@@ -46,6 +46,22 @@
     return {
       flocId_: Object,
 
+      /**
+       * Mock preference for FLoC toggle to always display as off and disabled
+       * as the feature has been removed from the codebase.
+       * TODO(crbug.com/1299720): Remove this and all the UI code which uses it.
+       */
+      prefFlocToggle_: {
+        type: Object,
+        value() {
+          return {
+            type: chrome.settingsPrivate.PrefType.BOOLEAN,
+            value: false,
+            userControlDisabled: true,
+          };
+        },
+      },
+
       privacySandboxSettings3Enabled_: {
         type: Boolean,
         value: () => loadTimeData.getBoolean('privacySandboxSettings3Enabled'),
@@ -98,13 +114,10 @@
     };
   }
 
-  static get observers() {
-    return ['onFlocChanged_(prefs.generated.floc_enabled.*)'];
-  }
-
   private flocId_: FlocIdentifier;
   private metricsBrowserProxy_: MetricsBrowserProxy =
       MetricsBrowserProxyImpl.getInstance();
+  private prefFlocToggle_: chrome.settingsPrivate.PrefObject;
   private privacySandboxBrowserProxy_: PrivacySandboxBrowserProxy =
       PrivacySandboxBrowserProxyImpl.getInstance();
   private privacySandboxSettings3Enabled_: boolean;
@@ -164,10 +177,6 @@
         TrustSafetyInteraction.OPENED_PRIVACY_SANDBOX);
   }
 
-  private onFlocChanged_() {
-    this.privacySandboxBrowserProxy_.getFlocId().then(id => this.flocId_ = id);
-  }
-
   private onResetFlocClick_() {
     this.privacySandboxBrowserProxy_.resetFlocId();
   }
@@ -192,13 +201,6 @@
     }
   }
 
-  private onFlocToggleButtonChange_(event: Event) {
-    const flocEnabled = (event.target as SettingsToggleButtonElement).checked;
-    this.metricsBrowserProxy_.recordAction(
-        flocEnabled ? 'Settings.PrivacySandbox.FlocEnabled' :
-                      'Settings.PrivacySandbox.FlocDisabled');
-  }
-
   private showFragment_(view: PrivacySandboxSettingsView): boolean {
     return this.privacySandboxSettingsView === view;
   }
diff --git a/chrome/browser/resources/side_panel/BUILD.gn b/chrome/browser/resources/side_panel/BUILD.gn
index 34750ad78..c3938a82 100644
--- a/chrome/browser/resources/side_panel/BUILD.gn
+++ b/chrome/browser/resources/side_panel/BUILD.gn
@@ -29,23 +29,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  input_files = [
-    "history_clusters/history_clusters.html",
-    "images/read_later_empty_dark.svg",
-    "images/read_later_empty.svg",
-    "reading_list/reading_list.html",
-    "bookmarks/bookmarks.html",
-    "read_anything/read_anything.html",
-    "side_panel.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  grd_prefix = "side_panel"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-}
-
 preprocess_if_expr("preprocess_src") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -108,3 +91,21 @@
     ":preprocess_src",
   ]
 }
+
+generate_grd("build_grd") {
+  input_files = [
+    "history_clusters/history_clusters.html",
+    "images/read_later_empty_dark.svg",
+    "images/read_later_empty.svg",
+    "reading_list/reading_list.html",
+    "bookmarks/bookmarks.html",
+    "read_anything/read_anything.html",
+    "side_panel.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  grd_prefix = "side_panel"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
diff --git a/chrome/browser/resources/signin/BUILD.gn b/chrome/browser/resources/signin/BUILD.gn
index 9cb4b0b..50e3f4b 100644
--- a/chrome/browser/resources/signin/BUILD.gn
+++ b/chrome/browser/resources/signin/BUILD.gn
@@ -34,6 +34,49 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
+html_to_wrapper("html_wrapper_files") {
+  in_files = html_files
+}
+
+css_to_wrapper("css_wrapper_files") {
+  in_files = css_files
+}
+
+preprocess_if_expr("preprocess") {
+  out_folder = "$target_gen_dir/$preprocess_folder"
+  in_files = ts_files
+}
+
+preprocess_if_expr("preprocess_gen") {
+  in_folder = target_gen_dir
+  out_folder = "$target_gen_dir/$preprocess_folder"
+  in_files = html_wrapper_files + css_wrapper_files
+  deps = [
+    ":css_wrapper_files",
+    ":html_wrapper_files",
+  ]
+}
+
+ts_library("build_ts") {
+  root_dir = "$target_gen_dir/$preprocess_folder"
+  out_dir = "$target_gen_dir/tsc"
+  composite = true
+  tsconfig_base = "tsconfig_base.json"
+  in_files = ts_files + html_wrapper_files + css_wrapper_files
+
+  definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
+
+  deps = [
+    "//third_party/polymer/v3_0:library",
+    "//ui/webui/resources:library",
+    "//ui/webui/resources/cr_components/customize_themes:build_ts",
+  ]
+  extra_deps = [
+    ":preprocess",
+    ":preprocess_gen",
+  ]
+}
+
 generate_grd("build_grd") {
   grd_prefix = "signin"
   out_grd = "$target_gen_dir/resources.grd"
@@ -76,48 +119,6 @@
   input_files_base_dir = rebase_path(".", "//")
 
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
-html_to_wrapper("html_wrapper_files") {
-  in_files = html_files
-}
-
-css_to_wrapper("css_wrapper_files") {
-  in_files = css_files
-}
-
-preprocess_if_expr("preprocess") {
-  out_folder = "$target_gen_dir/$preprocess_folder"
-  in_files = ts_files
-}
-
-preprocess_if_expr("preprocess_gen") {
-  in_folder = target_gen_dir
-  out_folder = "$target_gen_dir/$preprocess_folder"
-  in_files = html_wrapper_files + css_wrapper_files
-  deps = [
-    ":css_wrapper_files",
-    ":html_wrapper_files",
-  ]
-}
-
-ts_library("build_ts") {
-  root_dir = "$target_gen_dir/$preprocess_folder"
-  out_dir = "$target_gen_dir/tsc"
-  composite = true
-  tsconfig_base = "tsconfig_base.json"
-  in_files = ts_files + html_wrapper_files + css_wrapper_files
-
-  definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
-
-  deps = [
-    "//third_party/polymer/v3_0:library",
-    "//ui/webui/resources:library",
-    "//ui/webui/resources/cr_components/customize_themes:build_ts",
-  ]
-  extra_deps = [
-    ":preprocess",
-    ":preprocess_gen",
-  ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 0e749629..f661c4f 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -43,31 +43,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "profile_picker"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "profile_picker.html",
-    "images/left_banner_image.svg",
-    "images/right_banner_image.svg",
-    "images/dark_mode_left_banner_image.svg",
-    "images/dark_mode_right_banner_image.svg",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [
-      "profile_picker.rollup.js|profile_picker.js",
-      "lazy_load.rollup.js|lazy_load.js",
-    ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/$preprocess_folder"
   in_files = ts_files
@@ -129,3 +104,29 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "profile_picker"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "profile_picker.html",
+    "images/left_banner_image.svg",
+    "images/right_banner_image.svg",
+    "images/dark_mode_left_banner_image.svg",
+    "images/dark_mode_right_banner_image.svg",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [
+      "profile_picker.rollup.js|profile_picker.js",
+      "lazy_load.rollup.js|lazy_load.js",
+    ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/support_tool/BUILD.gn b/chrome/browser/resources/support_tool/BUILD.gn
index a73e9920..023b444 100644
--- a/chrome/browser/resources/support_tool/BUILD.gn
+++ b/chrome/browser/resources/support_tool/BUILD.gn
@@ -13,18 +13,6 @@
 
 resources_grd_file = "$target_gen_dir/resources.grd"
 
-generate_grd("build_grd") {
-  grd_prefix = "support_tool"
-  out_grd = resources_grd_file
-  input_files = html_files + [
-                  "support_tool_container.html",
-                  "url_generator_container.html",
-                ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 grit("resources") {
   enable_input_discovery_for_gn_analyze = false
   source = resources_grd_file
@@ -68,3 +56,16 @@
   ]
   definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "support_tool"
+  out_grd = resources_grd_file
+  input_files = html_files + [
+                  "support_tool_container.html",
+                  "url_generator_container.html",
+                ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/sync_file_system_internals/BUILD.gn b/chrome/browser/resources/sync_file_system_internals/BUILD.gn
index a22a599..b4a0db9 100644
--- a/chrome/browser/resources/sync_file_system_internals/BUILD.gn
+++ b/chrome/browser/resources/sync_file_system_internals/BUILD.gn
@@ -29,21 +29,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "sync_file_system_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [ "main.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [
-    "$target_gen_dir/$preprocess_manifest",
-    "$target_gen_dir/tsconfig.manifest",
-  ]
-  deps = [
-    ":build_ts",
-    ":preprocess",
-  ]
-}
-
 preprocess_if_expr("preprocess") {
   out_folder = "$target_gen_dir/preprocessed"
   out_manifest = "$target_gen_dir/$preprocess_manifest"
@@ -64,3 +49,17 @@
   deps = [ "//ui/webui/resources:library" ]
   definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "sync_file_system_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [ "main.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  manifest_files =
+      [ "$target_gen_dir/$preprocess_manifest" ] +
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  deps = [
+    ":build_ts",
+    ":preprocess",
+  ]
+}
diff --git a/chrome/browser/resources/tab_search/BUILD.gn b/chrome/browser/resources/tab_search/BUILD.gn
index 1873079..7558112 100644
--- a/chrome/browser/resources/tab_search/BUILD.gn
+++ b/chrome/browser/resources/tab_search/BUILD.gn
@@ -44,30 +44,6 @@
   }
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "tab_search"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "alert_indicators/tab_audio_muting_rounded.svg",
-    "alert_indicators/tab_audio_rounded.svg",
-    "alert_indicators/tab_media_recording.svg",
-    "tab_search.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_fuse_grdp" ]
-  grdp_files = [ "$target_gen_dir/fuse_resources.grdp" ]
-
-  if (optimize_webui) {
-    deps += [ ":build" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-    resource_path_rewrites = [ "tab_search.rollup.js|tab_search.js" ]
-  } else {
-    deps += [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-}
-
 generate_grd("build_fuse_grdp") {
   grd_prefix = "tab_search"
   out_grd = "$target_gen_dir/fuse_resources.grdp"
@@ -183,3 +159,28 @@
     ":preprocess_tabs",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "tab_search"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "alert_indicators/tab_audio_muting_rounded.svg",
+    "alert_indicators/tab_audio_rounded.svg",
+    "alert_indicators/tab_media_recording.svg",
+    "tab_search.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_fuse_grdp" ]
+  grdp_files = [ "$target_gen_dir/fuse_resources.grdp" ]
+
+  if (optimize_webui) {
+    deps += [ ":build" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+    resource_path_rewrites = [ "tab_search.rollup.js|tab_search.js" ]
+  } else {
+    deps += [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+}
diff --git a/chrome/browser/resources/tab_strip/BUILD.gn b/chrome/browser/resources/tab_strip/BUILD.gn
index 0035ce28..4a3f2f4 100644
--- a/chrome/browser/resources/tab_strip/BUILD.gn
+++ b/chrome/browser/resources/tab_strip/BUILD.gn
@@ -15,28 +15,6 @@
 
 preprocess_folder = "preprocessed"
 
-generate_grd("build_grd") {
-  grd_prefix = "tab_strip"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "alert_indicators/picture_in_picture_alt.svg",
-    "alert_indicators/serial_port.svg",
-    "alert_indicators/tab_audio_muting_rounded.svg",
-    "alert_indicators/tab_audio_rounded.svg",
-    "alert_indicators/tab_bluetooth_connected.svg",
-    "alert_indicators/tab_hid_connected.svg",
-    "alert_indicators/tab_media_capturing_with_arrow.svg",
-    "alert_indicators/tab_media_recording.svg",
-    "alert_indicators/tab_usb_connected.svg",
-    "alert_indicators/vr_headset.svg",
-    "tab_strip.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 copy("copy_mojo") {
   deps = [
     "//chrome/browser/ui/webui/tab_strip:mojo_bindings_webui_js",
@@ -104,3 +82,26 @@
     ":preprocess_src",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "tab_strip"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "alert_indicators/picture_in_picture_alt.svg",
+    "alert_indicators/serial_port.svg",
+    "alert_indicators/tab_audio_muting_rounded.svg",
+    "alert_indicators/tab_audio_rounded.svg",
+    "alert_indicators/tab_bluetooth_connected.svg",
+    "alert_indicators/tab_hid_connected.svg",
+    "alert_indicators/tab_media_capturing_with_arrow.svg",
+    "alert_indicators/tab_media_recording.svg",
+    "alert_indicators/tab_usb_connected.svg",
+    "alert_indicators/vr_headset.svg",
+    "tab_strip.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/usb_internals/BUILD.gn b/chrome/browser/resources/usb_internals/BUILD.gn
index 129dbea..530d86f 100644
--- a/chrome/browser/resources/usb_internals/BUILD.gn
+++ b/chrome/browser/resources/usb_internals/BUILD.gn
@@ -9,18 +9,6 @@
 
 resources_grd_file = "$target_gen_dir/resources.grd"
 
-generate_grd("build_grd") {
-  grd_prefix = "usb_internals"
-  out_grd = resources_grd_file
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [
-    "usb_internals.css",
-    "usb_internals.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 grit("resources") {
   enable_input_discovery_for_gn_analyze = false
   source = resources_grd_file
@@ -53,10 +41,10 @@
     "//services/device/public/mojom:usb_webui_js",
   ]
   sources = ts_files + [
+              "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/usb_internals/usb_internals.mojom-webui.js",
               "$root_gen_dir/mojom-webui/services/device/public/mojom/usb_device.mojom-webui.js",
               "$root_gen_dir/mojom-webui/services/device/public/mojom/usb_manager.mojom-webui.js",
               "$root_gen_dir/mojom-webui/services/device/public/mojom/usb_manager_test.mojom-webui.js",
-              "$root_gen_dir/mojom-webui/chrome/browser/ui/webui/usb_internals/usb_internals.mojom-webui.js",
             ]
   outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
@@ -81,3 +69,16 @@
     ":html_wrapper_files",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "usb_internals"
+  out_grd = resources_grd_file
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [
+    "usb_internals.css",
+    "usb_internals.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/chrome/browser/resources/webapks/BUILD.gn b/chrome/browser/resources/webapks/BUILD.gn
index 9d3462c..65ac2b5 100644
--- a/chrome/browser/resources/webapks/BUILD.gn
+++ b/chrome/browser/resources/webapks/BUILD.gn
@@ -20,7 +20,8 @@
   grd_prefix = "webapks"
   out_grd = "$target_gen_dir/resources.grd"
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   input_files = [
     "about_webapks.css",
     "about_webapks.html",
diff --git a/chrome/browser/resources/webui_gallery/BUILD.gn b/chrome/browser/resources/webui_gallery/BUILD.gn
index e0b73cf..507bf93 100644
--- a/chrome/browser/resources/webui_gallery/BUILD.gn
+++ b/chrome/browser/resources/webui_gallery/BUILD.gn
@@ -25,24 +25,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "webui_gallery"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "demos/demo.css",
-    "demos/cr_a11y_announcer_demo.html",
-    "demos/cr_button_demo.html",
-    "demos/cr_checkbox_demo.html",
-    "demos/cr_dialog_demo.html",
-    "demos/cr_radio_demo.html",
-    "demos/cr_toggle_demo.html",
-    "webui_gallery.html",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 html_to_wrapper("html_wrapper_files") {
   in_files = html_files
 }
@@ -66,3 +48,22 @@
     ":html_wrapper_files",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "webui_gallery"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "demos/demo.css",
+    "demos/cr_a11y_announcer_demo.html",
+    "demos/cr_button_demo.html",
+    "demos/cr_checkbox_demo.html",
+    "demos/cr_dialog_demo.html",
+    "demos/cr_radio_demo.html",
+    "demos/cr_toggle_demo.html",
+    "webui_gallery.html",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/chrome/browser/resources/webui_js_error/BUILD.gn b/chrome/browser/resources/webui_js_error/BUILD.gn
index 36b2ee1d..6675f56 100644
--- a/chrome/browser/resources/webui_js_error/BUILD.gn
+++ b/chrome/browser/resources/webui_js_error/BUILD.gn
@@ -32,21 +32,6 @@
   in_files = [ "webui_js_error.ts" ]
 }
 
-generate_grd("build_grd") {
-  input_files = [ "webui_js_error.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-  if (optimize_webui) {
-    deps = [ ":build" ]
-    resource_path_rewrites = [ "webui_js_error.rollup.js|webui_js_error.js" ]
-    manifest_files = [ "$target_gen_dir/$build_manifest" ]
-  } else {
-    deps = [ ":build_ts" ]
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  }
-  grd_prefix = "webui_js_error"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-}
-
 grit("resources") {
   defines = chrome_grit_defines
 
@@ -71,3 +56,19 @@
   deps = [ "//ui/webui/resources:library" ]
   extra_deps = [ ":preprocess" ]
 }
+
+generate_grd("build_grd") {
+  input_files = [ "webui_js_error.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+  if (optimize_webui) {
+    deps = [ ":build" ]
+    resource_path_rewrites = [ "webui_js_error.rollup.js|webui_js_error.js" ]
+    manifest_files = [ "$target_gen_dir/$build_manifest" ]
+  } else {
+    deps = [ ":build_ts" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  }
+  grd_prefix = "webui_js_error"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
diff --git a/chrome/browser/resources/welcome/BUILD.gn b/chrome/browser/resources/welcome/BUILD.gn
index 46910c1..044e47c 100644
--- a/chrome/browser/resources/welcome/BUILD.gn
+++ b/chrome/browser/resources/welcome/BUILD.gn
@@ -15,36 +15,6 @@
 
 preprocess_folder = "preprocessed"
 
-generate_grd("build_grd") {
-  grd_prefix = "welcome"
-  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
-  input_files = [
-    "images/background_svgs/bookmarks_background.svg",
-    "images/background_svgs/bookmarks_foreground.svg",
-    "images/background_svgs/devices_check.svg",
-    "images/background_svgs/devices.svg",
-    "images/background_svgs/hexagon.svg",
-    "images/background_svgs/lozenge.svg",
-    "images/background_svgs/password_field.svg",
-    "images/background_svgs/password.svg",
-    "images/background_svgs/square.svg",
-    "images/background_svgs/streamer_circle.svg",
-    "images/background_svgs/streamer_line.svg",
-    "images/background_svgs/triangle.svg",
-    "welcome.html",
-    "welcome.css",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-
-  if (is_chrome_branded) {
-    deps += [ ":build_icons_grdp" ]
-    grdp_files = [ "$target_gen_dir/icon_resources.grdp" ]
-  }
-}
-
 if (is_chrome_branded) {
   generate_grd("build_icons_grdp") {
     grd_prefix = "welcome_images"
@@ -129,3 +99,34 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "welcome"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+  input_files = [
+    "images/background_svgs/bookmarks_background.svg",
+    "images/background_svgs/bookmarks_foreground.svg",
+    "images/background_svgs/devices_check.svg",
+    "images/background_svgs/devices.svg",
+    "images/background_svgs/hexagon.svg",
+    "images/background_svgs/lozenge.svg",
+    "images/background_svgs/password_field.svg",
+    "images/background_svgs/password.svg",
+    "images/background_svgs/square.svg",
+    "images/background_svgs/streamer_circle.svg",
+    "images/background_svgs/streamer_line.svg",
+    "images/background_svgs/triangle.svg",
+    "welcome.html",
+    "welcome.css",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+
+  if (is_chrome_branded) {
+    deps += [ ":build_icons_grdp" ]
+    grdp_files = [ "$target_gen_dir/icon_resources.grdp" ]
+  }
+}
diff --git a/chrome/browser/resources/whats_new/BUILD.gn b/chrome/browser/resources/whats_new/BUILD.gn
index faf707e..bd987f8e 100644
--- a/chrome/browser/resources/whats_new/BUILD.gn
+++ b/chrome/browser/resources/whats_new/BUILD.gn
@@ -27,15 +27,6 @@
   output_dir = "$root_gen_dir/chrome"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "whats_new"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [ "whats_new.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 html_to_wrapper("html_wrapper_files") {
   in_files = [ "whats_new_app.html" ]
 }
@@ -68,3 +59,13 @@
     ":html_wrapper_files",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "whats_new"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [ "whats_new.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
index d052bf96..ffc4868 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_browsertest.cc
@@ -141,7 +141,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ClientSideDetectionHostPrerenderBrowserTest,
-                       PrerenderShouldNotAffectClientSideDetection) {
+                       DISABLED_PrerenderShouldNotAffectClientSideDetection) {
   FakeClientSideDetectionService fake_csd_service;
   fake_csd_service.SetModel(client_side_model());
 
@@ -188,7 +188,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ClientSideDetectionHostPrerenderBrowserTest,
-                       ClassifyPrerenderedPageAfterActivation) {
+                       DISABLED_ClassifyPrerenderedPageAfterActivation) {
   FakeClientSideDetectionService fake_csd_service;
   fake_csd_service.SetModel(client_side_model());
 
diff --git a/chrome/browser/sharesheet/sharesheet_service.cc b/chrome/browser/sharesheet/sharesheet_service.cc
index 4e2c658..1d13e75 100644
--- a/chrome/browser/sharesheet/sharesheet_service.cc
+++ b/chrome/browser/sharesheet/sharesheet_service.cc
@@ -392,8 +392,7 @@
   auto launch_source = apps::mojom::LaunchSource::kFromSharesheet;
   app_service_proxy_->LaunchAppWithIntent(
       base::UTF16ToUTF8(target_name),
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
                           /*prefer_container=*/true),
       std::move(intent), launch_source,
       apps::MakeWindowInfo(display::kDefaultDisplayId));
diff --git a/chrome/browser/signin/signin_features.cc b/chrome/browser/signin/signin_features.cc
index f85323c0..a8b508b3 100644
--- a/chrome/browser/signin/signin_features.cc
+++ b/chrome/browser/signin/signin_features.cc
@@ -4,6 +4,12 @@
 
 #include "chrome/browser/signin/signin_features.h"
 
+#if BUILDFLAG(IS_ANDROID)
+// Enables the FamilyLink feedback collection in Chrome Settings feedback tool.
+const base::Feature kEnableFamilyInfoFeedback{"EnableFamilyInfoFeedback",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
 // Enables the client-side processing of the HTTP response header
 // Google-Accounts-RemoveLocalAccount.
 const base::Feature kProcessGaiaRemoveLocalAccountHeader{
diff --git a/chrome/browser/signin/signin_features.h b/chrome/browser/signin/signin_features.h
index c0ecb097..1a0bd89 100644
--- a/chrome/browser/signin/signin_features.h
+++ b/chrome/browser/signin/signin_features.h
@@ -7,6 +7,10 @@
 
 #include "base/feature_list.h"
 
+#if BUILDFLAG(IS_ANDROID)
+extern const base::Feature kEnableFamilyInfoFeedback;
+#endif
+
 extern const base::Feature kProcessGaiaRemoveLocalAccountHeader;
 
 extern const base::Feature kSyncPromoAfterSigninIntercept;
diff --git a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
index 4c91bd9..950b9a2 100644
--- a/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_nigori_sync_test.cc
@@ -620,6 +620,82 @@
                   .Wait());
 }
 
+IN_PROC_BROWSER_TEST_F(
+    SingleClientNigoriSyncTest,
+    ShouldFollowRewritingKeystoreMigrationWhenDataDecryptable) {
+  // Setup with implicit passphrase.
+  const KeyParamsForTesting kPassphraseKeyParams =
+      Pbkdf2PassphraseKeyParamsForTesting("passphrase");
+  sync_pb::NigoriSpecifics specifics;
+  std::unique_ptr<syncer::CryptographerImpl> cryptographer =
+      syncer::CryptographerImpl::FromSingleKeyForTesting(
+          kPassphraseKeyParams.password,
+          kPassphraseKeyParams.derivation_params);
+  ASSERT_TRUE(cryptographer->Encrypt(cryptographer->ToProto().key_bag(),
+                                     specifics.mutable_encryption_keybag()));
+  SetNigoriInFakeServer(specifics, GetFakeServer());
+
+  // Mimic passwords encrypted with implicit passphrase stored by the server.
+  const password_manager::PasswordForm password_form1 =
+      passwords_helper::CreateTestPasswordForm(1);
+  passwords_helper::InjectEncryptedServerPassword(
+      password_form1, kPassphraseKeyParams.password,
+      kPassphraseKeyParams.derivation_params, GetFakeServer());
+
+  ASSERT_TRUE(SetupSync());
+  ASSERT_TRUE(
+      PassphraseRequiredStateChecker(GetSyncService(0), /*desired_state=*/true)
+          .Wait());
+
+  // Mimic that passphrase is provided by the user.
+  ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->SetDecryptionPassphrase(
+      kPassphraseKeyParams.password));
+  ASSERT_TRUE(PassphraseRequiredStateChecker(GetSyncService(0),
+                                             /*desired_stater=*/false)
+                  .Wait());
+  ASSERT_TRUE(WaitForPasswordForms({password_form1}));
+
+  // Add local passwords.
+  const password_manager::PasswordForm password_form2 =
+      passwords_helper::CreateTestPasswordForm(2);
+  passwords_helper::GetProfilePasswordStoreInterface(0)->AddLogin(
+      password_form2);
+
+  // Mimic server-side keystore migration:
+  // 1. Issue CLIENT_DATA_OBSOLETE.
+  // 2. Delete server-side passwords (without creating tombstones).
+  // 3. Rewrite server-side nigori with keystore one (this also triggers an
+  // invalidation, so client should see CLIENT_DATA_OBSOLETE).
+  GetFakeServer()->TriggerError(sync_pb::SyncEnums::CLIENT_DATA_OBSOLETE);
+  GetFakeServer()->DeleteAllEntitiesForModelType(syncer::PASSWORDS);
+
+  const std::vector<std::vector<uint8_t>>& keystore_keys =
+      GetFakeServer()->GetKeystoreKeys();
+  ASSERT_THAT(keystore_keys, SizeIs(1));
+  const KeyParamsForTesting kKeystoreKeyParams =
+      KeystoreKeyParamsForTesting(keystore_keys.back());
+  SetNigoriInFakeServer(BuildKeystoreNigoriSpecifics(
+                            /*keybag_keys_params=*/{kKeystoreKeyParams},
+                            /*keystore_decryptor_params*/ {kKeystoreKeyParams},
+                            /*keystore_key_params=*/kKeystoreKeyParams),
+                        GetFakeServer());
+  // Nigori change triggers invalidation, so client should observe
+  // CLIENT_DATA_OBSOLETE and stop the engine.
+  ASSERT_TRUE(syncer::SyncEngineStoppedChecker(GetSyncService(0)).Wait());
+
+  // Make server return SUCCESS so that sync can initialize.
+  GetFakeServer()->TriggerError(sync_pb::SyncEnums::SUCCESS);
+  ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization());
+
+  // Verify client and server side state. Both passwords should be stored and
+  // encrypted with keystore passphrase.
+  EXPECT_TRUE(WaitForPasswordForms({password_form1, password_form2}));
+  EXPECT_TRUE(ServerPasswordsEqualityChecker(
+                  {password_form1, password_form2}, kKeystoreKeyParams.password,
+                  kKeystoreKeyParams.derivation_params)
+                  .Wait());
+}
+
 // Performs initial sync for Nigori, but doesn't allow initialized Nigori to be
 // committed.
 IN_PROC_BROWSER_TEST_F(SingleClientNigoriSyncTestWithNotAwaitQuiescence,
diff --git a/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc b/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc
index 057e1ec9..62134baa 100644
--- a/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc
+++ b/chrome/browser/sync/test/lacros/sync_custom_passphrase_sharing_lacros_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include <utility>
 
+#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
 #include "chrome/browser/sync/test/integration/encryption_helper.h"
 #include "chrome/browser/sync/test/integration/passwords_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
@@ -12,6 +14,7 @@
 #include "chromeos/crosapi/mojom/sync.mojom.h"
 #include "chromeos/lacros/lacros_service.h"
 #include "components/sync/chromeos/explicit_passphrase_mojo_utils.h"
+#include "components/sync/engine/nigori/nigori.h"
 #include "components/sync/nigori/nigori_test_utils.h"
 #include "components/sync/test/fake_server/fake_server_nigori_helper.h"
 #include "content/public/test/browser_test.h"
@@ -26,12 +29,26 @@
 
 using testing::_;
 
+std::string ComputeKeyName(const syncer::Nigori& nigori) {
+  std::string key_name;
+  nigori.Permute(syncer::Nigori::Password, syncer::kNigoriKeyName, &key_name);
+  return key_name;
+}
+
 MATCHER_P(AccountKeyEq, expected_account_key, "") {
   const crosapi::mojom::AccountKeyPtr& given_account_key = arg;
   return given_account_key->id == expected_account_key.id &&
          given_account_key->account_type == expected_account_key.account_type;
 }
 
+MATCHER_P(MojoNigoriCanDecryptServerNigori, fake_server, "") {
+  const crosapi::mojom::NigoriKeyPtr& mojo_nigori = arg;
+  sync_pb::NigoriSpecifics server_specifics;
+  fake_server::GetServerNigori(fake_server, &server_specifics);
+  return mojo_nigori && ComputeKeyName(*syncer::NigoriFromMojo(*mojo_nigori)) ==
+                            server_specifics.encryption_keybag().key_name();
+}
+
 class MockSyncExplicitPassphraseClientAsh
     : public crosapi::mojom::SyncExplicitPassphraseClient {
  public:
@@ -209,4 +226,71 @@
   EXPECT_TRUE(PasswordFormsChecker(0, {password_form}).Wait());
 }
 
+IN_PROC_BROWSER_TEST_F(SyncCustomPassphraseSharingLacrosBrowserTest,
+                       ShouldExposeEncryptionKeyWhenSetDecryptionPassphrase) {
+  if (!IsServiceAvailable()) {
+    GTEST_SKIP() << "Unsupported Ash version.";
+  }
+
+  ASSERT_TRUE(SetupSync());
+
+  // Mimic custom passphrase being set by other client.
+  const syncer::KeyParamsForTesting kKeyParams =
+      syncer::ScryptPassphraseKeyParamsForTesting("hunter2");
+  fake_server::SetNigoriInFakeServer(
+      syncer::BuildCustomPassphraseNigoriSpecifics(kKeyParams),
+      GetFakeServer());
+
+  // Mimic Ash received the remote update and indicates that passphrase is
+  // required.
+  client_observer()->OnPassphraseRequired();
+
+  ASSERT_TRUE(
+      PassphraseRequiredStateChecker(GetSyncService(0), /*desired_state=*/true)
+          .Wait());
+
+  // Mimic that user enters the passphrase, key should be exposed to Ash.
+  base::RunLoop run_loop;
+  EXPECT_CALL(
+      *client_ash(),
+      SetDecryptionNigoriKey(AccountKeyEq(GetSyncingUserAccountKey()),
+                             MojoNigoriCanDecryptServerNigori(GetFakeServer())))
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
+
+  ASSERT_TRUE(GetSyncService(0)->GetUserSettings()->SetDecryptionPassphrase(
+      kKeyParams.password));
+  ASSERT_TRUE(
+      PassphraseRequiredStateChecker(GetSyncService(0), /*desired_state=*/false)
+          .Wait());
+
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(SyncCustomPassphraseSharingLacrosBrowserTest,
+                       ShouldExposeEncryptionKeyWhenSetEncryptionPassphrase) {
+  if (!IsServiceAvailable()) {
+    GTEST_SKIP() << "Unsupported Ash version.";
+  }
+
+  ASSERT_TRUE(SetupSync());
+
+  const std::string kPassphrase = "hunter2";
+  GetSyncService(0)->GetUserSettings()->SetEncryptionPassphrase(kPassphrase);
+  ASSERT_TRUE(
+      ServerPassphraseTypeChecker(syncer::PassphraseType::kCustomPassphrase)
+          .Wait());
+
+  // Mimic Ash received the remote update and indicates that passphrase is
+  // required, key should be exposed to Ash.
+  base::RunLoop run_loop;
+  EXPECT_CALL(
+      *client_ash(),
+      SetDecryptionNigoriKey(AccountKeyEq(GetSyncingUserAccountKey()),
+                             MojoNigoriCanDecryptServerNigori(GetFakeServer())))
+      .WillOnce(base::test::RunOnceClosure(run_loop.QuitClosure()));
+
+  client_observer()->OnPassphraseRequired();
+  run_loop.Run();
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 342cc96..c1bd46f3 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -297,12 +297,6 @@
     "webui/policy/policy_ui.h",
     "webui/policy/policy_ui_handler.cc",
     "webui/policy/policy_ui_handler.h",
-    "webui/policy/status_provider/cloud_policy_core_status_provider.cc",
-    "webui/policy/status_provider/cloud_policy_core_status_provider.h",
-    "webui/policy/status_provider/status_provider_util.cc",
-    "webui/policy/status_provider/status_provider_util.h",
-    "webui/policy/status_provider/user_cloud_policy_status_provider.cc",
-    "webui/policy/status_provider/user_cloud_policy_status_provider.h",
     "webui/predictors/predictors_handler.cc",
     "webui/predictors/predictors_handler.h",
     "webui/predictors/predictors_ui.cc",
@@ -2858,16 +2852,6 @@
       "webui/nearby_share/nearby_share_dialog_ui.h",
       "webui/nearby_share/shared_resources.cc",
       "webui/nearby_share/shared_resources.h",
-      "webui/policy/status_provider/device_active_directory_policy_status_provider.cc",
-      "webui/policy/status_provider/device_active_directory_policy_status_provider.h",
-      "webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.cc",
-      "webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h",
-      "webui/policy/status_provider/device_local_account_policy_status_provider.cc",
-      "webui/policy/status_provider/device_local_account_policy_status_provider.h",
-      "webui/policy/status_provider/user_active_directory_policy_status_provider.cc",
-      "webui/policy/status_provider/user_active_directory_policy_status_provider.h",
-      "webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.cc",
-      "webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.h",
       "webui/settings/ash/app_management/app_management_uma.h",
       "webui/settings/ash/calculator/size_calculator.cc",
       "webui/settings/ash/calculator/size_calculator.h",
@@ -3332,10 +3316,6 @@
       "views/frame/immersive_mode_controller_chromeos.h",
       "views/profiles/lacros_first_run_signed_in_flow_controller.cc",
       "views/profiles/lacros_first_run_signed_in_flow_controller.h",
-      "webui/policy/status_provider/device_policy_status_provider_lacros.cc",
-      "webui/policy/status_provider/device_policy_status_provider_lacros.h",
-      "webui/policy/status_provider/user_policy_status_provider_lacros.cc",
-      "webui/policy/status_provider/user_policy_status_provider_lacros.h",
       "webui/signin/profile_picker_lacros_sign_in_provider.cc",
       "webui/signin/profile_picker_lacros_sign_in_provider.h",
       "window_sizer/window_sizer_chromeos.cc",
@@ -3851,8 +3831,6 @@
       "webui/conflicts/conflicts_handler.h",
       "webui/conflicts/conflicts_ui.cc",
       "webui/conflicts/conflicts_ui.h",
-      "webui/policy/status_provider/updater_status_provider.cc",
-      "webui/policy/status_provider/updater_status_provider.h",
       "webui/sandbox/sandbox_handler.cc",
       "webui/sandbox/sandbox_handler.h",
       "webui/settings/chrome_cleanup_handler_win.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 710cfd1..8949061 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -1607,6 +1607,9 @@
       <message name="IDS_LANGUAGES_SRP_SUBTITLE" desc="Subtitle warning a user that the language of their keyboard will not change if they change the application language of Chrome on Android.">
         Your keyboard won’t change
       </message>
+      <message name="IDS_LANGUAGES_MORE_LANGUAGES" desc="Text used in a language picker to hide languages that a user is less likely to select. [CHAR_LIMIT=32]">
+        More languages
+      </message>
       <message name="IDS_LANGUAGES_SRP_LOADING_TEXT" desc="Text to display while a language pack is being downloaded.">
         Loading <ph name="LANG">%1$s<ex>Hindi</ex></ph>
       </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_LANGUAGES_MORE_LANGUAGES.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_LANGUAGES_MORE_LANGUAGES.png.sha1
new file mode 100644
index 0000000..384af66
--- /dev/null
+++ b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_LANGUAGES_MORE_LANGUAGES.png.sha1
@@ -0,0 +1 @@
+8de5c4e75ae36be026a8a95fdcd0aac8409c5352
\ No newline at end of file
diff --git a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
index f52d964..d8de74c 100644
--- a/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
+++ b/chrome/browser/ui/app_list/app_list_client_impl_browsertest.cc
@@ -118,10 +118,8 @@
         content::NotificationService::AllSources());
     apps::AppServiceProxyFactory::GetForProfile(profile())->Launch(
         extension_app->id(),
-        apps::GetEventFlags(
-            apps::mojom::LaunchContainer::kLaunchContainerWindow,
-            WindowOpenDisposition::NEW_WINDOW,
-            false /* preferred_containner */),
+        apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                            false /* preferred_containner */),
         apps::mojom::LaunchSource::kFromTest,
         apps::MakeWindowInfo(
             display::Screen::GetScreen()->GetPrimaryDisplay().id()));
diff --git a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
index 17dcc55..87d9d5e 100644
--- a/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
+++ b/chrome/browser/ui/ash/arc_open_url_delegate_impl.cc
@@ -264,19 +264,17 @@
     return;
   }
 
-  int event_flags = apps::GetEventFlags(
-      apps::mojom::LaunchContainer::kLaunchContainerWindow,
-      WindowOpenDisposition::NEW_WINDOW, /*prefer_container=*/false);
+  int event_flags = apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                        /*prefer_container=*/false);
   apps::AppServiceProxy* proxy =
       apps::AppServiceProxyFactory::GetForProfile(profile);
 
   proxy->AppRegistryCache().ForOneApp(
       *app_id, [&event_flags](const apps::AppUpdate& update) {
         if (update.WindowMode() == apps::WindowMode::kBrowser) {
-          event_flags = apps::GetEventFlags(
-              apps::mojom::LaunchContainer::kLaunchContainerTab,
-              WindowOpenDisposition::NEW_FOREGROUND_TAB,
-              /*prefer_container=*/false);
+          event_flags =
+              apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                  /*prefer_container=*/false);
         }
       });
 
@@ -407,17 +405,15 @@
 
   apps::mojom::IntentPtr intent = ConvertLaunchIntent(arc_intent);
 
-  auto launch_container = apps::mojom::LaunchContainer::kLaunchContainerWindow;
   auto disposition = WindowOpenDisposition::NEW_WINDOW;
   proxy->AppRegistryCache().ForOneApp(
-      app_id, [&launch_container, &disposition](const apps::AppUpdate& update) {
+      app_id, [&disposition](const apps::AppUpdate& update) {
         if (update.WindowMode() == apps::WindowMode::kBrowser) {
-          launch_container = apps::mojom::LaunchContainer::kLaunchContainerTab;
           disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
         }
       });
 
-  int event_flags = apps::GetEventFlags(launch_container, disposition,
+  int event_flags = apps::GetEventFlags(disposition,
                                         /*prefer_container=*/false);
 
   proxy->LaunchAppWithIntent(app_id, event_flags, std::move(intent),
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 68e834c..0d2e10f 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -386,12 +386,10 @@
       return;
     }
 
-    proxy->Launch(
-        update.AppId(),
-        apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerNone,
-                            WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                            /*preferred_containner=*/true),
-        apps::mojom::LaunchSource::kFromKeyboard);
+    proxy->Launch(update.AppId(),
+                  apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                      /*prefer_container=*/true),
+                  apps::mojom::LaunchSource::kFromKeyboard);
   };
 
   bool result = proxy->AppRegistryCache().ForOneApp(
@@ -427,9 +425,8 @@
 
     proxy->LaunchAppWithFiles(
         update.AppId(),
-        apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerNone,
-                            WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                            /*preferred_containner=*/true),
+        apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                            /*prefer_container=*/true),
         apps::mojom::LaunchSource::kFromKeyboard, std::move(launch_files));
   };
 
diff --git a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
index 1b61065..9ba9772 100644
--- a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
@@ -710,12 +710,12 @@
                                         kTestLogicalWindow};
   // Create windows that will be associated with the tasks. Without this,
   // GetAppMenuItems() will only return an empty list.
-  std::vector<std::unique_ptr<exo::ShellSurface>> test_windows;
+  std::vector<std::unique_ptr<exo::ClientControlledShellSurface>> test_windows;
 
   for (int task_id = 1; task_id <= 7; task_id++) {
     test_windows.push_back(exo::test::ShellSurfaceBuilder({640, 480})
                                .SetCentered()
-                               .BuildShellSurface());
+                               .BuildClientControlledShellSurface());
 
     aura::Window* aura_window =
         test_windows[task_id - 1]->GetWidget()->GetNativeWindow();
diff --git a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
index 17680766..94148ee1 100644
--- a/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/chrome_shelf_controller_browsertest.cc
@@ -1180,10 +1180,8 @@
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
   LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                          true /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                  true /* prefer_containner */));
   EXPECT_EQ(++tab_count, tab_strip->count());
   ash::ShelfID shortcut_id = CreateShortcut("app1");
   EXPECT_EQ(ash::STATUS_RUNNING, shelf_model()->ItemByID(shortcut_id)->status);
@@ -1199,10 +1197,8 @@
 // an unpinned hosted app web contents.
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppIDForUnpinnedHostedApp) {
   const extensions::Extension* extension = LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                          true /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                  true /* prefer_containner */));
 
   int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
   ash::ShelfID browser_id = shelf_model()->items()[browser_index].id;
@@ -1338,10 +1334,8 @@
   TabStripModel* tab_strip = browser()->tab_strip_model();
   int tab_count = tab_strip->count();
   LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_BACKGROUND_TAB,
-                          true /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_BACKGROUND_TAB,
+                                  true /* prefer_containner */));
   EXPECT_EQ(++tab_count, tab_strip->count());
   controller_->LaunchApp(ash::ShelfID(last_loaded_extension_id()),
                          ash::LAUNCH_FROM_UNKNOWN, 0,
@@ -1618,10 +1612,8 @@
 IN_PROC_BROWSER_TEST_F(ShelfAppBrowserTest, AppWindowRestoreBehaviorTest) {
   // Open an App, maximized its window, and close it.
   const Extension* extension = LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                  false /* prefer_containner */));
   Browser* app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   BrowserWindow* window = app_browser->window();
@@ -1632,10 +1624,8 @@
 
   // Reopen the App. It should start maximized. Un-maximize it and close it.
   extension = LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                  false /* prefer_containner */));
   app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   window = app_browser->window();
@@ -1648,10 +1638,8 @@
 
   // Reopen the App. It should start un-maximized.
   extension = LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                  false /* prefer_containner */));
   app_browser = FindBrowserForApp(extension->id());
   ASSERT_TRUE(app_browser);
   window = app_browser->window();
@@ -1668,10 +1656,8 @@
   EXPECT_EQ(0u, running_browser);
 
   const Extension* extension = LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                  false /* prefer_containner */));
   ASSERT_TRUE(extension);
 
   // No new browser should get detected, even though one more is running.
@@ -1679,14 +1665,12 @@
   EXPECT_EQ(++running_browser, chrome::GetTotalBrowserCount());
 
   auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile());
-  proxy->Launch(
-      extension->id(),
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                          true /* prefer_containner */),
-      apps::mojom::LaunchSource::kFromTest,
-      apps::MakeWindowInfo(
-          display::Screen::GetScreen()->GetPrimaryDisplay().id()));
+  proxy->Launch(extension->id(),
+                apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                    true /* prefer_containner */),
+                apps::mojom::LaunchSource::kFromTest,
+                apps::MakeWindowInfo(
+                    display::Screen::GetScreen()->GetPrimaryDisplay().id()));
   proxy->FlushMojoCallsForTesting();
 
   // A new browser should get detected and one more should be running.
@@ -1699,10 +1683,8 @@
                        EnumerateAllBrowsersAndTabs) {
   // Create at least one browser.
   LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                          true /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                  true /* prefer_containner */));
   size_t browsers = BrowserShortcutMenuItemCount(false);
   size_t tabs = BrowserShortcutMenuItemCount(true);
 
@@ -1721,10 +1703,8 @@
 
   // Create only a tab.
   LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                          true /* prefer_containner */));
+      "app1", apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                                  true /* prefer_containner */));
 
   EXPECT_EQ(browsers, BrowserShortcutMenuItemCount(false));
   EXPECT_EQ(++tabs, BrowserShortcutMenuItemCount(true));
@@ -2074,11 +2054,9 @@
   EXPECT_TRUE(browser1->window()->IsActive());
 
   // Create another app and make sure that none of our browsers is active.
-  LoadAndLaunchExtension(
-      "app1",
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          false /* prefer_containner */));
+  LoadAndLaunchExtension("app1",
+                         apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                             false /* prefer_containner */));
   EXPECT_FALSE(browser1->window()->IsActive());
   EXPECT_FALSE(browser2->window()->IsActive());
 
@@ -2355,8 +2333,7 @@
   // Create a windowed application.
   apps::AppServiceProxyFactory::GetForProfile(profile())->Launch(
       extensions::kWebStoreAppId,
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerTab,
-                          WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_FOREGROUND_TAB,
                           true /* prefer_containner */),
       apps::mojom::LaunchSource::kFromTest,
       apps::MakeWindowInfo(
diff --git a/chrome/browser/ui/ash/system_tray_client_impl.cc b/chrome/browser/ui/ash/system_tray_client_impl.cc
index cff4494..a04b829 100644
--- a/chrome/browser/ui/ash/system_tray_client_impl.cc
+++ b/chrome/browser/ui/ash/system_tray_client_impl.cc
@@ -744,12 +744,10 @@
   }
 
   // Launch web app.
-  proxy->LaunchAppWithUrl(
-      web_app::kGoogleCalendarAppId,
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
-                          /*prefer_container=*/true),
-      official_url, apps::mojom::LaunchSource::kFromShelf);
+  proxy->LaunchAppWithUrl(web_app::kGoogleCalendarAppId,
+                          apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                              /*prefer_container=*/true),
+                          official_url, apps::mojom::LaunchSource::kFromShelf);
   opened_pwa = true;
 }
 
diff --git a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
index bf4d3905..a345ed3 100644
--- a/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
+++ b/chrome/browser/ui/web_applications/system_web_app_ui_utils.cc
@@ -157,9 +157,8 @@
       apps::AppServiceProxyFactory::GetForProfile(profile_for_launch);
   DCHECK(app_service);
 
-  auto event_flags = apps::GetEventFlags(
-      apps::mojom::LaunchContainer::kLaunchContainerNone,
-      WindowOpenDisposition::NEW_WINDOW, /* prefer_container */ false);
+  auto event_flags = apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
+                                         /* prefer_container */ false);
 
   if (!params.launch_paths.empty()) {
     DCHECK(!params.url.has_value())
diff --git a/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc b/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
index d3659b1..bfb5614 100644
--- a/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
+++ b/chrome/browser/ui/webui/certificate_provisioning_ui_handler.cc
@@ -100,6 +100,24 @@
   NOTREACHED();
 }
 
+// Returns the status message of the process.
+// The status message is expanded by the failure message if the process failed
+// and the error message is non-empty.
+std::u16string MakeStatusMessage(
+    bool did_fail,
+    CertProvisioningProcessState state,
+    const absl::optional<std::string>& failure_message) {
+  if (!did_fail) {
+    return StateToText(state);
+  }
+  std::u16string status_message =
+      StateToText(CertProvisioningProcessState::kFailed);
+  if (failure_message.has_value()) {
+    status_message += base::UTF8ToUTF16(": " + failure_message.value());
+  }
+  return status_message;
+}
+
 // Returns a localized representation of the last update time as a delay (e.g.
 // "5 minutes ago".
 std::u16string GetTimeSinceLastUpdate(base::Time last_update_time) {
@@ -229,16 +247,9 @@
         "lastUnsuccessfulMessage",
         GetMessageFromBackendError(process->last_backend_server_error));
     entry.SetIntKey("stateId", static_cast<int>(process->state));
-
-    if (process->did_fail) {
-      // For failed processes `state` contains the last good state. Show an
-      // error as a text and keep the detailed information in the stateId.
-      entry.SetStringKey("status",
-                         StateToText(CertProvisioningProcessState::kFailed));
-    } else {
-      entry.SetStringKey("status", StateToText(process->state));
-    }
-
+    entry.SetStringKey("status",
+                       MakeStatusMessage(process->did_fail, process->state,
+                                         process->failure_message));
     entry.SetStringKey("publicKey",
                        x509_certificate_model::ProcessRawSubjectPublicKeyInfo(
                            process->public_key));
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
index 0f4562f..e6da57a 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -35,12 +35,12 @@
 #include "chrome/browser/policy/policy_ui_utils.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/schema_registry_service.h"
+#include "chrome/browser/policy/status_provider/cloud_policy_core_status_provider.h"
+#include "chrome/browser/policy/status_provider/status_provider_util.h"
+#include "chrome/browser/policy/status_provider/user_cloud_policy_status_provider.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
 #include "chrome/browser/ui/managed_ui.h"
-#include "chrome/browser/ui/webui/policy/status_provider/cloud_policy_core_status_provider.h"
-#include "chrome/browser/ui/webui/policy/status_provider/status_provider_util.h"
-#include "chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/enterprise/browser/controller/browser_dm_token_storage.h"
@@ -94,19 +94,19 @@
 #include "chrome/browser/ash/policy/off_hours/device_off_hours_controller.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/ui/webui/policy/status_provider/device_active_directory_policy_status_provider.h"
-#include "chrome/browser/ui/webui/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
-#include "chrome/browser/ui/webui/policy/status_provider/device_local_account_policy_status_provider.h"
-#include "chrome/browser/ui/webui/policy/status_provider/user_active_directory_policy_status_provider.h"
-#include "chrome/browser/ui/webui/policy/status_provider/user_cloud_policy_status_provider_chromeos.h"
+#include "chrome/browser/policy/status_provider/device_active_directory_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/device_cloud_policy_status_provider_chromeos.h"
+#include "chrome/browser/policy/status_provider/device_local_account_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_active_directory_policy_status_provider.h"
+#include "chrome/browser/policy/status_provider/user_cloud_policy_status_provider_chromeos.h"
 #include "components/user_manager/user_manager.h"
 #else
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-#include "chrome/browser/ui/webui/policy/status_provider/device_policy_status_provider_lacros.h"
-#include "chrome/browser/ui/webui/policy/status_provider/user_policy_status_provider_lacros.h"
+#include "chrome/browser/policy/status_provider/device_policy_status_provider_lacros.h"
+#include "chrome/browser/policy/status_provider/user_policy_status_provider_lacros.h"
 #include "chromeos/crosapi/mojom/policy_service.mojom.h"
 #include "chromeos/lacros/lacros_service.h"
 #endif
@@ -124,7 +124,7 @@
 #include <DSRole.h>
 
 #include "chrome/browser/google/google_update_policy_fetcher_win.h"
-#include "chrome/browser/ui/webui/policy/status_provider/updater_status_provider.h"
+#include "chrome/browser/policy/status_provider/updater_status_provider.h"
 #include "chrome/install_static/install_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/web_applications/app_service/web_apps_browsertest.cc b/chrome/browser/web_applications/app_service/web_apps_browsertest.cc
index e1ccad2..dd5fc58b 100644
--- a/chrome/browser/web_applications/app_service/web_apps_browsertest.cc
+++ b/chrome/browser/web_applications/app_service/web_apps_browsertest.cc
@@ -64,8 +64,7 @@
   apps::mojom::IntentPtr intent = apps_util::CreateShareIntentFromFiles(
       profile, std::move(file_paths), std::move(content_types));
   const int32_t event_flags =
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
                           /*prefer_container=*/true);
   apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithIntent(
       app_id, event_flags, std::move(intent),
@@ -100,8 +99,7 @@
       /*share_title=*/"Subject");
 
   const int32_t event_flags =
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
                           /*prefer_container=*/true);
   apps::AppServiceProxyFactory::GetForProfile(profile)->LaunchAppWithIntent(
       app_id, event_flags, std::move(intent),
@@ -144,8 +142,7 @@
       });
 
   const int32_t event_flags =
-      apps::GetEventFlags(apps::mojom::LaunchContainer::kLaunchContainerWindow,
-                          WindowOpenDisposition::NEW_WINDOW,
+      apps::GetEventFlags(WindowOpenDisposition::NEW_WINDOW,
                           /*prefer_container=*/true);
   proxy->Launch(app_id, event_flags, apps::mojom::LaunchSource::kUnknown,
                 apps::MakeWindowInfo(display::kDefaultDisplayId));
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index bc4202b..1c70bbdc 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-main-1656611842-ec98b627272820fd57d6592bebe434339f3b1e33.profdata
+chrome-linux-main-1656655133-9ca3e0c13a6d7673375f3bfe06136515934edcbf.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 1d0b5a2..0e384bee 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-main-1656611842-0d5c930c81e851348c3722be42a3bf8f98c0ffd4.profdata
+chrome-mac-main-1656655133-1d61366e0514513aa08ecbe8be600cefb9f9e66f.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 2688014..b65e060 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-main-1656622803-d6ba1cb8ce093fd9089d6e6168a7b272f9d9cabd.profdata
+chrome-win32-main-1656644169-9ed682b74d9d001dcb7f7fdf1c3775321d143c17.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 31815fd5b..f51b162 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-main-1656622803-9af9e8a429810f92e20d6b19e9c4546591730efd.profdata
+chrome-win64-main-1656655133-7b041b4cb3c66c62b77d03e645d6909a943585d3.profdata
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index cce5343..d9ebfef 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -291,6 +291,17 @@
   };
   callback GetArcAppCallback = void (ArcAppDict package);
 
+  dictionary ArcAppKillsDict {
+    double oom;
+    double lmkdForeground;
+    double lmkdPerceptible;
+    double lmkdCached;
+    double pressureForeground;
+    double pressurePerceptible;
+    double pressureCached;
+  };
+  callback GetArcAppKillsCallback = void (ArcAppKillsDict counts);
+
   dictionary ArcPackageDict {
     DOMString packageName;
     long packageVersion;
@@ -820,6 +831,10 @@
     [supportsPromises] static void getArcApp(DOMString appId,
                                              GetArcAppCallback callback);
 
+    // Gets counts of how many ARC apps have been killed, by priority.
+    [supportsPromises] static void getArcAppKills(
+        GetArcAppKillsCallback callback);
+
     // Gets information about requested ARC package.
     [supportsPromises] static void getArcPackage(
         DOMString packageName,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index af84567..7518e19 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6442,7 +6442,6 @@
       "../browser/policy/policy_path_parser_unittest.cc",
       "../browser/policy/serial_allow_usb_devices_for_urls_policy_handler_unittest.cc",
       "../browser/policy/webhid_device_policy_handler_unittest.cc",
-      "../browser/privacy_sandbox/generated_floc_pref_unittest.cc",
       "../browser/profile_resetter/profile_resetter_unittest.cc",
       "../browser/profile_resetter/reset_report_uploader_unittest.cc",
       "../browser/profiles/guest_profile_creation_logger_unittest.cc",
@@ -7904,9 +7903,6 @@
         "//chrome/browser/chromeos/extensions/telemetry/api:unit_tests",
         "//chrome/common/chromeos/extensions",
         "//chromeos/dbus/image_burner",
-        "//content/public/browser",
-        "//net",
-        "//net:test_support",
       ]
     } else {
       sources += [
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js
index b1d7ecb4..0c8c2a1 100644
--- a/chrome/test/data/extensions/api_test/autotest_private/test.js
+++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -1273,7 +1273,21 @@
               chrome.test.callbackPass(function() {
           }));
     });
-  },
+  }
+];
+
+var arcProcessTests = [
+  async function requestLowMemoryKillCounts() {
+    const counts = await promisify(chrome.autotestPrivate.getArcAppKills);
+    chrome.test.assertEq(counts.oom, 1);
+    chrome.test.assertEq(counts.lmkdForeground, 2);
+    chrome.test.assertEq(counts.lmkdPerceptible, 3);
+    chrome.test.assertEq(counts.lmkdCached, 4);
+    chrome.test.assertEq(counts.pressureForeground, 5);
+    chrome.test.assertEq(counts.pressurePerceptible, 6);
+    chrome.test.assertEq(counts.pressureCached, 7);
+    chrome.test.succeed();
+  }
 ];
 
 var policyTests = [
@@ -1566,6 +1580,7 @@
 var test_suites = {
   'default': defaultTests,
   'arcEnabled': arcEnabledTests,
+  'arcProcess': arcProcessTests,
   'enterprisePolicies': policyTests,
   'arcPerformanceTracing': arcPerformanceTracingTests,
   'overviewDefault': overviewTests,
diff --git a/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/manifest.json b/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/manifest.json
index 7575bba..8279107a 100644
--- a/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/manifest.json
+++ b/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/manifest.json
@@ -14,7 +14,7 @@
     "permissions": [
       "fileManagerPrivate",
       {
-        "fileSystem": ["requestFileSystem"]
+        "fileSystem": ["requestFileSystem", "write"]
       },
       "unlimitedStorage"
     ]
diff --git a/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/test.js b/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/test.js
index b44946a..0f8cab46 100644
--- a/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/test.js
+++ b/chrome/test/data/extensions/api_test/file_browser/dlp_metadata/test.js
@@ -27,13 +27,14 @@
 async function getFileSystem(volumeType) {
   const volume = await getVolumeMetadataByType(volumeType);
   return new Promise((resolve, reject) => {
-    chrome.fileSystem.requestFileSystem({volumeId: volume.volumeId}, fs => {
-      if (chrome.runtime.lastError) {
-        reject(chrome.runtime.lastError.message);
-        return;
-      }
-      resolve(fs);
-    });
+    chrome.fileSystem.requestFileSystem(
+        {volumeId: volume.volumeId, writable: true}, fs => {
+          if (chrome.runtime.lastError) {
+            reject(chrome.runtime.lastError.message);
+            return;
+          }
+          resolve(fs);
+        });
   });
 }
 
@@ -65,19 +66,40 @@
   return Promise.all(paths.map(path => getFileEntry(volumeType, path)));
 }
 
-chrome.test.runTests([async function getDlpMetadata() {
-  const testEntries = await getFileEntries(
-      'testing',
-      ['blocked_file.txt', 'unrestricted_file.txt', 'untracked_file.txt']);
-  chrome.test.assertEq(3, testEntries.length);
-  chrome.fileManagerPrivate.getDlpMetadata(
-      testEntries, chrome.test.callbackPass(dlpMetadata => {
-        chrome.test.assertEq(
-            [
-              {isDlpRestricted: true, sourceUrl: 'https://example1.com'},
-              {isDlpRestricted: false, sourceUrl: 'https://example2.com'},
-              {isDlpRestricted: false, sourceUrl: ''}
-            ],
-            dlpMetadata);
-      }))
-}]);
+chrome.test.runTests([
+  async function getDlpMetadata() {
+    const testEntries = await getFileEntries(
+        'testing',
+        ['blocked_file.txt', 'unrestricted_file.txt', 'untracked_file.txt']);
+    chrome.test.assertEq(3, testEntries.length);
+    chrome.fileManagerPrivate.getDlpMetadata(
+        testEntries, chrome.test.callbackPass(dlpMetadata => {
+          chrome.test.assertEq(
+              [
+                {isDlpRestricted: true, sourceUrl: 'https://example1.com'},
+                {isDlpRestricted: false, sourceUrl: 'https://example2.com'},
+                {isDlpRestricted: false, sourceUrl: ''}
+              ],
+              dlpMetadata);
+        }))
+  },
+  async function getDlpMetadata_Error() {
+    // Get the file.
+    const [file] = await getFileEntries('testing', ['blocked_file.txt']);
+    // Delete the file. Even though 'blocked_file.txt' is restricted by DLP,
+    // once it doesn't exist anymore an empty DlpMetadata object should be
+    // returned.
+    await new Promise((resolve, reject) => file.remove(resolve, reject));
+    chrome.fileManagerPrivate.getDlpMetadata(
+        [file], chrome.test.callbackPass(dlpMetadata => {
+          chrome.test.assertEq(
+              [{isDlpRestricted: false, sourceUrl: ''}], dlpMetadata);
+        }))
+  },
+  async function getDlpMetadata_Empty() {
+    chrome.fileManagerPrivate.getDlpMetadata(
+        [], chrome.test.callbackPass(dlpMetadata => {
+          chrome.test.assertEq(0, dlpMetadata.length);
+        }))
+  }
+]);
diff --git a/chrome/test/data/pdf/BUILD.gn b/chrome/test/data/pdf/BUILD.gn
index 8d9d659..a8236e6 100644
--- a/chrome/test/data/pdf/BUILD.gn
+++ b/chrome/test/data/pdf/BUILD.gn
@@ -9,15 +9,6 @@
 
 assert(enable_pdf, "enable_pdf check failed")
 
-generate_grd("build_grdp") {
-  grd_prefix = "pdf"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "pdf"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -80,3 +71,13 @@
   deps = [ "//chrome/browser/resources/pdf:build_ts" ]
   extra_deps = [ "../webui:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "pdf"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "pdf"
+}
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index e4ab3d2..c6e453c8 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -386,6 +386,62 @@
   deps = [ "..:web_ui_test_mojom_js_module" ]
 }
 
+# TypeScript related targets
+
+checked_in_dts_files = [
+  "chai_assert.d.ts",
+  "test_browser_proxy.d.ts",
+]
+
+# Copies checked-in .d.ts files to the preprocess folder so that they are
+# discovered by TSC the same way generated .d.ts files are.
+copy("copy_checked_in_dts_files") {
+  sources = checked_in_dts_files
+  outputs = [ "$target_gen_dir/tsc/{{source_target_relative}}" ]
+}
+
+ts_definitions("generate_definitions") {
+  root_dir = "./"
+  out_dir = "$target_gen_dir/tsc"
+  js_files = [
+    "fake_chrome_event.js",
+    "mock_controller.js",
+    "mock_timer.js",
+    "mojo_webui_test_support.js",
+    "test_plural_string_proxy.js",
+    "test_store.js",
+    "test_util.js",
+  ]
+  extra_deps = [
+    ":copy_checked_in_dts_files",
+    "//ui/webui/resources:generate_definitions",
+  ]
+}
+
+ts_library("build_ts") {
+  root_dir = "."
+  out_dir = "$target_gen_dir/tsc"
+  composite = true
+  tsconfig_base = "tsconfig_base.json"
+  path_mappings = [ "chrome://webui-test/*|" +
+                    rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
+                                target_gen_dir) ]
+  in_files = [
+    "chrome_timeticks_test.ts",
+    "color_provider_css_colors_test.ts",
+    "cr_focus_row_behavior_test.ts",
+    "resources/list_property_update_behavior_tests.ts",
+    "resources/list_property_update_mixin_tests.ts",
+    "text_defaults_test.ts",
+  ]
+  deps = [ "//ui/webui/resources:library" ]
+  extra_deps = [ ":generate_definitions" ]
+  definitions = [
+    "//tools/typescript/definitions/chrome_send.d.ts",
+    "//tools/typescript/definitions/chrome_timeticks.d.ts",
+  ]
+}
+
 generate_grd("build_grd") {
   testonly = true
   grd_prefix = "webui_generated_test"
@@ -515,61 +571,6 @@
     ]
   }
 
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
-# TypeScript related targets
-
-checked_in_dts_files = [
-  "chai_assert.d.ts",
-  "test_browser_proxy.d.ts",
-]
-
-# Copies checked-in .d.ts files to the preprocess folder so that they are
-# discovered by TSC the same way generated .d.ts files are.
-copy("copy_checked_in_dts_files") {
-  sources = checked_in_dts_files
-  outputs = [ "$target_gen_dir/tsc/{{source_target_relative}}" ]
-}
-
-ts_definitions("generate_definitions") {
-  root_dir = "./"
-  out_dir = "$target_gen_dir/tsc"
-  js_files = [
-    "fake_chrome_event.js",
-    "mock_controller.js",
-    "mock_timer.js",
-    "mojo_webui_test_support.js",
-    "test_plural_string_proxy.js",
-    "test_store.js",
-    "test_util.js",
-  ]
-  extra_deps = [
-    ":copy_checked_in_dts_files",
-    "//ui/webui/resources:generate_definitions",
-  ]
-}
-
-ts_library("build_ts") {
-  root_dir = "."
-  out_dir = "$target_gen_dir/tsc"
-  composite = true
-  tsconfig_base = "tsconfig_base.json"
-  path_mappings = [ "chrome://webui-test/*|" +
-                    rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
-                                target_gen_dir) ]
-  in_files = [
-    "chrome_timeticks_test.ts",
-    "color_provider_css_colors_test.ts",
-    "cr_focus_row_behavior_test.ts",
-    "resources/list_property_update_behavior_tests.ts",
-    "resources/list_property_update_mixin_tests.ts",
-    "text_defaults_test.ts",
-  ]
-  deps = [ "//ui/webui/resources:library" ]
-  extra_deps = [ ":generate_definitions" ]
-  definitions = [
-    "//tools/typescript/definitions/chrome_send.d.ts",
-    "//tools/typescript/definitions/chrome_timeticks.d.ts",
-  ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
diff --git a/chrome/test/data/webui/access_code_cast/BUILD.gn b/chrome/test/data/webui/access_code_cast/BUILD.gn
index 5d988706..8b8e6fd 100644
--- a/chrome/test/data/webui/access_code_cast/BUILD.gn
+++ b/chrome/test/data/webui/access_code_cast/BUILD.gn
@@ -5,23 +5,15 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_access_code_cast"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "access_code_cast"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
   tsconfig_base = "tsconfig_base.json"
   path_mappings = [
     "chrome://access-code-cast/*|" +
-        rebase_path("$root_gen_dir/chrome/browser/resources/access_code_cast/tsc/*",
-                    target_gen_dir),
+        rebase_path(
+            "$root_gen_dir/chrome/browser/resources/access_code_cast/tsc/*",
+            target_gen_dir),
     "chrome://webui-test/*|" +
         rebase_path("$root_gen_dir/chrome/test/data/webui/tsc/*",
                     target_gen_dir),
@@ -35,4 +27,14 @@
   ]
   deps = [ "//chrome/browser/resources/access_code_cast:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
-}
\ No newline at end of file
+}
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_access_code_cast"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "access_code_cast"
+}
diff --git a/chrome/test/data/webui/app_settings/BUILD.gn b/chrome/test/data/webui/app_settings/BUILD.gn
index f0e750d7..5cb6c52b 100644
--- a/chrome/test/data/webui/app_settings/BUILD.gn
+++ b/chrome/test/data/webui/app_settings/BUILD.gn
@@ -7,15 +7,6 @@
 
 assert(is_win || is_mac || is_linux || is_fuchsia)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_app_settings"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "app_settings"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -36,3 +27,13 @@
   deps = [ "//chrome/browser/resources/app_settings:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_app_settings"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "app_settings"
+}
diff --git a/chrome/test/data/webui/bookmarks/BUILD.gn b/chrome/test/data/webui/bookmarks/BUILD.gn
index c39f327..b2b4bd6 100644
--- a/chrome/test/data/webui/bookmarks/BUILD.gn
+++ b/chrome/test/data/webui/bookmarks/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_bookmarks"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "bookmarks"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -61,3 +52,13 @@
   ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_bookmarks"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "bookmarks"
+}
diff --git a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
index 557b9169..f2a42c0 100644
--- a/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
+++ b/chrome/test/data/webui/chromeos/emoji_picker/emoji_picker_test.js
@@ -383,14 +383,14 @@
       search.search = 'face with tears of joy';
 
       await waitForCondition(
-          () => search.emojiResults.length > 0, 'no search get any results',
+          () => search.getNumSearchResults() > 0, 'no search get any results',
           1000);
-      assertGT(search.emojiResults.length, 0);
+      assertGT(search.getNumSearchResults(), 0);
     });
     test('finds no results for garbage search', async () => {
       const search = findInEmojiPicker('emoji-search');
       search.search = 'THIS string should not match anything';
-      assertEquals(search.emojiResults.length, 0);
+      assertEquals(search.getNumSearchResults(), 0);
     });
   });
 });
diff --git a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
index a792732..ebbb905 100644
--- a/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
@@ -6,15 +6,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_chromeos_personalization_app"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "chromeos/personalization_app"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -65,3 +56,13 @@
   deps = [ "//ash/webui/personalization_app/resources:build_ts" ]
   extra_deps = [ "../..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_chromeos_personalization_app"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "chromeos/personalization_app"
+}
diff --git a/chrome/test/data/webui/commander/BUILD.gn b/chrome/test/data/webui/commander/BUILD.gn
index 81271b5..377c22b 100644
--- a/chrome/test/data/webui/commander/BUILD.gn
+++ b/chrome/test/data/webui/commander/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_commander"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "commander"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -33,3 +24,13 @@
   deps = [ "//chrome/browser/resources/commander:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_commander"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "commander"
+}
diff --git a/chrome/test/data/webui/cr_components/BUILD.gn b/chrome/test/data/webui/cr_components/BUILD.gn
index 85f6fb9..e6125124 100644
--- a/chrome/test/data/webui/cr_components/BUILD.gn
+++ b/chrome/test/data/webui/cr_components/BUILD.gn
@@ -51,15 +51,6 @@
   outputs = [ "$preprocessed_folder/{{source_target_relative}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_cr_components"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "cr_components"
-}
-
 ts_library("build_ts") {
   root_dir = preprocessed_folder
   out_dir = "$target_gen_dir/tsc"
@@ -88,3 +79,13 @@
     "..:generate_definitions",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_cr_components"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "cr_components"
+}
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn
index 9588bbb..eaccde7 100644
--- a/chrome/test/data/webui/cr_elements/BUILD.gn
+++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -8,15 +8,6 @@
 
 assert(!is_android && !is_ios)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_cr_elements"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "cr_elements"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -82,3 +73,13 @@
   deps = [ "//ui/webui/resources:library" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_cr_elements"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "cr_elements"
+}
diff --git a/chrome/test/data/webui/discards/BUILD.gn b/chrome/test/data/webui/discards/BUILD.gn
index 657a381..b165663 100644
--- a/chrome/test/data/webui/discards/BUILD.gn
+++ b/chrome/test/data/webui/discards/BUILD.gn
@@ -7,15 +7,6 @@
 
 assert(!is_android)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_discards"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "discards"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -33,3 +24,13 @@
   deps = [ "//chrome/browser/resources/discards:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_discards"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "discards"
+}
diff --git a/chrome/test/data/webui/downloads/BUILD.gn b/chrome/test/data/webui/downloads/BUILD.gn
index 3993f00..75edd48f 100644
--- a/chrome/test/data/webui/downloads/BUILD.gn
+++ b/chrome/test/data/webui/downloads/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_downloads"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "downloads"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -36,3 +27,13 @@
   deps = [ "//chrome/browser/resources/downloads:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_downloads"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "downloads"
+}
diff --git a/chrome/test/data/webui/extensions/BUILD.gn b/chrome/test/data/webui/extensions/BUILD.gn
index adafc57..81df08a 100644
--- a/chrome/test/data/webui/extensions/BUILD.gn
+++ b/chrome/test/data/webui/extensions/BUILD.gn
@@ -75,15 +75,6 @@
   outputs = [ "$preprocessed_folder/{{source_target_relative}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_extensions"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "extensions"
-}
-
 ts_library("build_ts") {
   root_dir = preprocessed_folder
   out_dir = "$target_gen_dir/tsc"
@@ -110,3 +101,13 @@
     "..:generate_definitions",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_extensions"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "extensions"
+}
diff --git a/chrome/test/data/webui/history/BUILD.gn b/chrome/test/data/webui/history/BUILD.gn
index e8ce73c..019f4d0 100644
--- a/chrome/test/data/webui/history/BUILD.gn
+++ b/chrome/test/data/webui/history/BUILD.gn
@@ -28,15 +28,6 @@
   "test_util.ts",
 ]
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_history"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "history"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -54,3 +45,13 @@
   deps = [ "//chrome/browser/resources/history:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_history"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "history"
+}
diff --git a/chrome/test/data/webui/js/BUILD.gn b/chrome/test/data/webui/js/BUILD.gn
index 507ad1c..bf1b4e6 100644
--- a/chrome/test/data/webui/js/BUILD.gn
+++ b/chrome/test/data/webui/js/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_js"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "js"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -47,3 +38,13 @@
   ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_js"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "js"
+}
diff --git a/chrome/test/data/webui/media_router/BUILD.gn b/chrome/test/data/webui/media_router/BUILD.gn
index 15c69b86..60515c19 100644
--- a/chrome/test/data/webui/media_router/BUILD.gn
+++ b/chrome/test/data/webui/media_router/BUILD.gn
@@ -9,15 +9,6 @@
 assert(!is_android)
 assert(is_chrome_branded)
 
-generate_grd("build_grdp") {
-  grd_prefix = "media_router"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "media_router"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -37,3 +28,13 @@
   deps = [ "//chrome/browser/resources/media_router/cast_feedback:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "media_router"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "media_router"
+}
diff --git a/chrome/test/data/webui/metrics_reporter/BUILD.gn b/chrome/test/data/webui/metrics_reporter/BUILD.gn
index 917d641..ff0643c 100644
--- a/chrome/test/data/webui/metrics_reporter/BUILD.gn
+++ b/chrome/test/data/webui/metrics_reporter/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_metrics_reporter"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "metrics_reporter"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -30,3 +21,13 @@
   deps = [ "//ui/webui/resources/js/metrics_reporter:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_metrics_reporter"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "metrics_reporter"
+}
diff --git a/chrome/test/data/webui/new_tab_page/BUILD.gn b/chrome/test/data/webui/new_tab_page/BUILD.gn
index e121598..10b99ab 100644
--- a/chrome/test/data/webui/new_tab_page/BUILD.gn
+++ b/chrome/test/data/webui/new_tab_page/BUILD.gn
@@ -27,15 +27,6 @@
                            "voice_search_overlay_test.ts",
                          ] + modules_test_files + realbox_test_files
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_new_tab_page"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "new_tab_page"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -58,3 +49,13 @@
   deps = [ "//chrome/browser/resources/new_tab_page:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_new_tab_page"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "new_tab_page"
+}
diff --git a/chrome/test/data/webui/print_preview/BUILD.gn b/chrome/test/data/webui/print_preview/BUILD.gn
index e934e76..26e3828 100644
--- a/chrome/test/data/webui/print_preview/BUILD.gn
+++ b/chrome/test/data/webui/print_preview/BUILD.gn
@@ -87,14 +87,6 @@
   preprocessed_tests += [ "link_container_test.ts" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_print_preview"
-  out_grd = "$target_gen_dir/resources.grdp"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "print_preview"
-}
-
 preprocessed_folder = "$target_gen_dir/preprocessed"
 
 preprocess_if_expr("preprocess") {
@@ -142,3 +134,12 @@
     "..:generate_definitions",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_print_preview"
+  out_grd = "$target_gen_dir/resources.grdp"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "print_preview"
+}
diff --git a/chrome/test/data/webui/privacy_sandbox/BUILD.gn b/chrome/test/data/webui/privacy_sandbox/BUILD.gn
index 137aef3..836b7ba5 100644
--- a/chrome/test/data/webui/privacy_sandbox/BUILD.gn
+++ b/chrome/test/data/webui/privacy_sandbox/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_privacy_sandbox"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "privacy_sandbox"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -31,3 +22,13 @@
   deps = [ "//chrome/browser/resources/privacy_sandbox:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_privacy_sandbox"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "privacy_sandbox"
+}
diff --git a/chrome/test/data/webui/settings/BUILD.gn b/chrome/test/data/webui/settings/BUILD.gn
index 1afbc2d..e646f2f 100644
--- a/chrome/test/data/webui/settings/BUILD.gn
+++ b/chrome/test/data/webui/settings/BUILD.gn
@@ -187,14 +187,6 @@
   outputs = [ "$preprocessed_folder/{{source_target_relative}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_settings"
-  out_grd = "$target_gen_dir/resources.grdp"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "settings"
-}
-
 ts_library("build_ts") {
   root_dir = preprocessed_folder
   out_dir = "$target_gen_dir/tsc"
@@ -224,3 +216,12 @@
     "..:generate_definitions",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_settings"
+  out_grd = "$target_gen_dir/resources.grdp"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "settings"
+}
diff --git a/chrome/test/data/webui/settings/privacy_sandbox_test.ts b/chrome/test/data/webui/settings/privacy_sandbox_test.ts
index 1bd0b37e..7b84531 100644
--- a/chrome/test/data/webui/settings/privacy_sandbox_test.ts
+++ b/chrome/test/data/webui/settings/privacy_sandbox_test.ts
@@ -101,8 +101,6 @@
         (document.createElement('privacy-sandbox-app'));
     document.body.appendChild(page);
 
-    page.prefs = {generated: {floc_enabled: {value: true}}};
-
     return flushTasks();
   });
 
@@ -126,7 +124,6 @@
           manually_controlled: {value: false},
           manually_controlled_v2: {value: false},
         },
-        generated: {floc_enabled: {value: true}}
       };
       await flushTasks();
       metricsBrowserProxy.resetResolver('recordAction');
@@ -205,37 +202,6 @@
     page.shadowRoot!.querySelector<HTMLElement>('#resetFlocIdButton')!.click();
     return testPrivacySandboxBrowserProxy.whenCalled('resetFlocId');
   });
-
-  test('prefObserver', async function() {
-    await testPrivacySandboxBrowserProxy.whenCalled('getFlocId');
-    testPrivacySandboxBrowserProxy.resetResolver('getFlocId');
-
-    // When the FLoC generated preference is changed, the page should re-query
-    // for the FLoC id.
-    testPrivacySandboxBrowserProxy.resetResolver('getFlocId');
-    page.set('prefs.generated.floc_enabled.value', false);
-    await testPrivacySandboxBrowserProxy.whenCalled('getFlocId');
-  });
-
-  test('userActions', async function() {
-    page.shadowRoot!.querySelector<HTMLElement>('#flocToggleButton')!.click();
-    assertEquals(
-        'Settings.PrivacySandbox.FlocDisabled',
-        await metricsBrowserProxy.whenCalled('recordAction'));
-    metricsBrowserProxy.resetResolver('recordAction');
-
-    page.shadowRoot!.querySelector<HTMLElement>('#flocToggleButton')!.click();
-    assertEquals(
-        'Settings.PrivacySandbox.FlocEnabled',
-        await metricsBrowserProxy.whenCalled('recordAction'));
-    metricsBrowserProxy.resetResolver('recordAction');
-
-    // Ensure that an action is only recorded in response to interaction with
-    // the toggle, and not for the generated preference changing.
-    page.set('prefs.generated.floc_enabled.value', false);
-    await flushTasks();
-    assertEquals(0, metricsBrowserProxy.getCallCount('recordAction'));
-  });
 });
 
 suite('PrivacySandboxSettings3', function() {
diff --git a/chrome/test/data/webui/side_panel/BUILD.gn b/chrome/test/data/webui/side_panel/BUILD.gn
index 847b106f..e18e9e3 100644
--- a/chrome/test/data/webui/side_panel/BUILD.gn
+++ b/chrome/test/data/webui/side_panel/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_side_panel"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "side_panel"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -45,3 +36,13 @@
   deps = [ "//chrome/browser/resources/side_panel:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_side_panel"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "side_panel"
+}
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn
index 15c2863d..eacfab3 100644
--- a/chrome/test/data/webui/signin/BUILD.gn
+++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -59,14 +59,6 @@
   outputs = [ "$preprocessed_folder/{{source_target_relative}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_signin"
-  out_grd = "$target_gen_dir/resources.grdp"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "signin"
-}
-
 ts_library("build_ts") {
   root_dir = preprocessed_folder
   out_dir = "$target_gen_dir/tsc"
@@ -105,3 +97,12 @@
     "..:generate_definitions",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_signin"
+  out_grd = "$target_gen_dir/resources.grdp"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "signin"
+}
diff --git a/chrome/test/data/webui/support_tool/BUILD.gn b/chrome/test/data/webui/support_tool/BUILD.gn
index 1fbcc8f..e060261f 100644
--- a/chrome/test/data/webui/support_tool/BUILD.gn
+++ b/chrome/test/data/webui/support_tool/BUILD.gn
@@ -7,15 +7,6 @@
 
 assert(!is_android)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_support_tool"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "support_tool"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -32,3 +23,13 @@
   deps = [ "//chrome/browser/resources/support_tool:build_ts" ]
   extra_deps = [ "../:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_support_tool"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "support_tool"
+}
diff --git a/chrome/test/data/webui/tab_search/BUILD.gn b/chrome/test/data/webui/tab_search/BUILD.gn
index 0aa3a48..f625cfc2 100644
--- a/chrome/test/data/webui/tab_search/BUILD.gn
+++ b/chrome/test/data/webui/tab_search/BUILD.gn
@@ -5,15 +5,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_tab_search"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "tab_search"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -47,3 +38,13 @@
   ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_tab_search"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "tab_search"
+}
diff --git a/chrome/test/data/webui/tab_strip/BUILD.gn b/chrome/test/data/webui/tab_strip/BUILD.gn
index ea142a18..ccd5d61 100644
--- a/chrome/test/data/webui/tab_strip/BUILD.gn
+++ b/chrome/test/data/webui/tab_strip/BUILD.gn
@@ -8,15 +8,6 @@
 
 assert(enable_webui_tab_strip)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_tab_strip"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "tab_strip"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -43,3 +34,13 @@
   deps = [ "//chrome/browser/resources/tab_strip:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_tab_strip"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "tab_strip"
+}
diff --git a/chrome/test/data/webui/welcome/BUILD.gn b/chrome/test/data/webui/welcome/BUILD.gn
index d172965..49e3baa 100644
--- a/chrome/test/data/webui/welcome/BUILD.gn
+++ b/chrome/test/data/webui/welcome/BUILD.gn
@@ -8,15 +8,6 @@
 
 assert(!is_chromeos_ash && !is_android)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_welcome"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "welcome"
-}
-
 ts_library("build_ts") {
   root_dir = "./"
   out_dir = "$target_gen_dir/tsc"
@@ -50,3 +41,13 @@
   deps = [ "//chrome/browser/resources/welcome:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_welcome"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "welcome"
+}
diff --git a/chrome/test/data/webui/whats_new/BUILD.gn b/chrome/test/data/webui/whats_new/BUILD.gn
index 46c683f..19d242f 100644
--- a/chrome/test/data/webui/whats_new/BUILD.gn
+++ b/chrome/test/data/webui/whats_new/BUILD.gn
@@ -7,15 +7,6 @@
 
 assert(!is_android)
 
-generate_grd("build_grdp") {
-  grd_prefix = "webui_whats_new"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "whats_new"
-}
-
 ts_library("build_ts") {
   root_dir = "."
   out_dir = "$target_gen_dir/tsc"
@@ -32,3 +23,13 @@
   deps = [ "//chrome/browser/resources/whats_new:build_ts" ]
   extra_deps = [ "..:generate_definitions" ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "webui_whats_new"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "whats_new"
+}
diff --git a/chromeos/crosapi/mojom/cert_provisioning.mojom b/chromeos/crosapi/mojom/cert_provisioning.mojom
index 3de5fef..b1b12207 100644
--- a/chromeos/crosapi/mojom/cert_provisioning.mojom
+++ b/chromeos/crosapi/mojom/cert_provisioning.mojom
@@ -61,6 +61,9 @@
   // RequiredClientCertificateForDevice policy, contains “false” if by
   // RequiredClientCertificateForUser.
   bool is_device_wide@7 = false;
+  // Describes the reason for failure in case a worker enters the failed state.
+  [MinVersion=1]
+  string? failure_message@8;
 };
 
 // This interface is implemented by classes that want to register themself as
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index 85392bc..0166279 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -52,6 +52,7 @@
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper.h"
 #include "third_party/skia/include/utils/SkNoDrawCanvas.h"
 #include "ui/aura/client/aura_constants.h"
@@ -126,16 +127,8 @@
 }  // namespace
 
 TEST_F(ClientControlledShellSurfaceTest, SetPinned) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
   shell_surface->SetPinned(chromeos::WindowPinType::kTrustedPinned);
   EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
@@ -151,14 +144,8 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetSystemUiVisibility) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
   shell_surface->SetSystemUiVisibility(true);
   EXPECT_TRUE(
@@ -172,15 +159,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetTopInset) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ASSERT_TRUE(window);
@@ -191,36 +172,12 @@
   EXPECT_EQ(top_inset_height, window->GetProperty(aura::client::kTopViewInset));
 }
 
-TEST_F(ClientControlledShellSurfaceTest, ModalWindowDefaultActive) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
-  ASSERT_FALSE(shell_surface->GetWidget());
-  shell_surface->SetSystemModal(true);
-  surface->Commit();
-
-  EXPECT_TRUE(ash::Shell::IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-}
-
 TEST_F(ClientControlledShellSurfaceTest, UpdateModalWindow) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetInputRegion(cc::Region())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen());
   EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
 
@@ -232,7 +189,7 @@
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   child->Attach(child_buffer.get());
   std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
+      display->CreateSubSurface(child.get(), surface));
   surface->SetSubSurfacePosition(child.get(), gfx::PointF(10, 10));
   child->Commit();
   surface->Commit();
@@ -278,14 +235,12 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        ModalWindowSetSystemModalBeforeCommit) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetInputRegion(cc::Region())
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Set SetSystemModal before any commit happens. Widget is not created at
   // this time.
@@ -306,33 +261,19 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        NonSystemModalContainerCantChangeModality) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-
-  shell_surface->SetSystemModal(true);
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetInputRegion(cc::Region())
+                           .EnableSystemModal()
+                           .BuildClientControlledShellSurface();
   // It is expected that a non system modal container is unable to set a system
   // modal.
   EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SurfaceShadow) {
-  gfx::Size buffer_size(128, 128);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({128, 128})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
 
   // 1) Initial state, no shadow (SurfaceFrameType is NONE);
@@ -340,12 +281,8 @@
   std::unique_ptr<Display> display(new Display);
 
   // 2) Just creating a sub surface won't create a shadow.
-  std::unique_ptr<Surface> child = display->CreateSurface();
-  std::unique_ptr<Buffer> child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  child->Attach(child_buffer.get());
-  std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
+  auto* child =
+      test::ShellSurfaceBuilder::AddChildSurface(surface, {0, 0, 128, 128});
   surface->Commit();
 
   EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
@@ -394,20 +331,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowWithStateChange) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
   const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
+  // Position the widget at 10,10 so that we get non zero offset.
+  auto shell_surface = exo::test::ShellSurfaceBuilder(content_size)
+                           .SetGeometry({gfx::Point(10, 10), content_size})
+                           .SetFrame(SurfaceFrameType::SHADOW)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // In parent coordinates.
   const gfx::Rect shadow_bounds(gfx::Point(-10, -10), content_size);
@@ -448,21 +378,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowWithTransform) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
   const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-
+  // Position the widget at 10,10 so that we get non zero offset.
+  auto shell_surface = exo::test::ShellSurfaceBuilder(content_size)
+                           .SetGeometry({gfx::Point(10, 10), content_size})
+                           .SetFrame(SurfaceFrameType::SHADOW)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
 
@@ -480,19 +402,12 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowStartMaximized) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetFrame(SurfaceFrameType::SHADOW)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   views::Widget* widget = shell_surface->GetWidget();
   aura::Window* window = widget->GetNativeWindow();
 
@@ -516,30 +431,24 @@
 TEST_F(ClientControlledShellSurfaceTest, Frame) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
-  display::DisplayManager* display_manager =
-      ash::Shell::Get()->display_manager();
-
-  std::unique_ptr<Surface> surface(new Surface);
-
   gfx::Rect client_bounds(20, 50, 300, 200);
   gfx::Rect fullscreen_bounds(0, 0, 800, 600);
   // The window bounds is the client bounds + frame size.
   gfx::Rect normal_window_bounds(20, 18, 300, 232);
 
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({client_bounds.size()})
+                           .SetGeometry(client_bounds)
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   shell_surface->SetSystemUiVisibility(true);  // disable shelf.
-
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(client_bounds);
-  surface->SetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
 
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  display::DisplayManager* display_manager =
+      ash::Shell::Get()->display_manager();
+
   views::Widget* widget = shell_surface->GetWidget();
   ash::NonClientFrameViewAsh* frame_view =
       static_cast<ash::NonClientFrameViewAsh*>(
@@ -681,20 +590,14 @@
 TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
-  std::unique_ptr<Surface> surface = std::make_unique<Surface>();
-
-  gfx::Rect fullscreen_bounds(0, 0, 800, 600);
-
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Maximized
+  gfx::Rect fullscreen_bounds(0, 0, 800, 600);
   shell_surface->SetMaximized();
   shell_surface->SetGeometry(fullscreen_bounds);
   surface->Commit();
@@ -721,13 +624,10 @@
        NoSynthesizedEventsForPixelCoordinates) {
   TestEventHandler event_handler;
 
-  gfx::Size buffer_size(400, 400);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  auto surface = std::make_unique<Surface>();
-  surface->Attach(buffer.get());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({400, 400})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   // Pixel coordinates add a transform to the underlying layer.
   shell_surface->set_client_submits_surfaces_in_pixel_coordinates(true);
 
@@ -760,24 +660,21 @@
 
 TEST_F(ClientControlledShellSurfaceTest, CompositorLockInRotation) {
   UpdateDisplay("800x600");
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
   ash::Shell* shell = ash::Shell::Get();
   shell->tablet_mode_controller()->SetEnabledForTest(true);
-
-  // Start in maximized.
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  surface->Commit();
-
   gfx::Rect maximum_bounds =
       display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
-  shell_surface->SetGeometry(maximum_bounds);
+
+  // Start in maximized.
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({800, 600})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetGeometry(maximum_bounds)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
   shell_surface->SetOrientation(Orientation::LANDSCAPE);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   ui::Compositor* compositor =
@@ -800,15 +697,8 @@
 // key while shell surface is active.
 TEST_F(ClientControlledShellSurfaceTest,
        KeyboardNavigationWithUnifiedSystemTray) {
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({800, 600})
+                           .BuildClientControlledShellSurface();
 
   EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
 
@@ -832,15 +722,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, Maximize) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
   shell_surface->SetMaximized();
   EXPECT_FALSE(HasBackdrop());
@@ -876,15 +760,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, Restore) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
   // Note: Remove contents to avoid issues with maximize animations in tests.
   shell_surface->SetMaximized();
@@ -899,16 +777,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetFullscreen) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  shell_surface->SetFullscreen(true);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kFullscreen)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_TRUE(HasBackdrop());
 
   // We always show backdrop becaues the window can be cropped.
@@ -933,15 +806,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ToggleFullscreen) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
 
   shell_surface->SetMaximized();
@@ -968,16 +835,9 @@
   int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
   display::SetInternalDisplayIds({display_id});
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), false /* is_modal */,
-      true /* default_scale_cancelation */));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .EnableDefaultScaleCancellation()
+                           .BuildClientControlledShellSurface();
   gfx::Transform transform;
   transform.Scale(1.0 / scale, 1.0 / scale);
 
@@ -1014,15 +874,8 @@
   display_manager->OnNativeDisplaysChanged(display_info_list);
   display_manager->UpdateInternalManagedDisplayModeListForTest();
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .BuildClientControlledShellSurface();
 
   gfx::Transform transform;
   transform.Scale(1.0 / scale, 1.0 / scale);
@@ -1033,17 +886,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, MouseAndTouchTarget) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  const gfx::Rect original_bounds(0, 0, 256, 256);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetGeometry({0, 0, 256, 256})
+                           .BuildClientControlledShellSurface();
 
   EXPECT_TRUE(shell_surface->CanResize());
 
@@ -1083,15 +928,9 @@
 // The shell surface in SystemModal container should be unresizable.
 TEST_F(ClientControlledShellSurfaceTest,
        ShellSurfaceInSystemModalIsUnresizable) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetUseSystemModalContainer()
+                           .BuildClientControlledShellSurface();
 
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 }
@@ -1099,20 +938,12 @@
 // The shell surface in SystemModal container should be a target
 // at the edge.
 TEST_F(ClientControlledShellSurfaceTest, ShellSurfaceInSystemModalHitTest) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
-
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 0, 0));
-  shell_surface->SetGeometry(display.bounds());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetGeometry(display.bounds())
+                           .SetInputRegion(gfx::Rect(0, 0, 0, 0))
+                           .BuildClientControlledShellSurface();
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   aura::Window* root = window->GetRootWindow();
@@ -1130,18 +961,11 @@
   UpdateDisplay("807x607");
   ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer1(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface1(new Surface);
   auto shell_surface1 =
-      exo_test_helper()->CreateClientControlledShellSurface(surface1.get());
-  // Start in maximized.
-  shell_surface1->SetGeometry(gfx::Rect(0, 0, 800, 600));
-  shell_surface1->SetMaximized();
-  surface1->Attach(buffer1.get());
-  surface1->Commit();
-
+      exo::test::ShellSurfaceBuilder({800, 600})
+          .SetGeometry({0, 0, 800, 600})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
   aura::Window* window1 = shell_surface1->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state1 = ash::WindowState::Get(window1);
   ash::ClientControlledState* state1 = static_cast<ash::ClientControlledState*>(
@@ -1181,17 +1005,10 @@
 // The shell surface in SystemModal container should not become target
 // at the edge.
 TEST_F(ClientControlledShellSurfaceTest, ClientIniatedResize) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
-
-  gfx::Size window_size(100, 100);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(window_size));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({100, 100})
+                           .SetGeometry(gfx::Rect({0, 0, 100, 100}))
+                           .BuildClientControlledShellSurface();
   EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
   shell_surface->StartDrag(HTTOP, gfx::PointF(0, 0));
 
@@ -1217,16 +1034,15 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ResizabilityAndSizeConstraints) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMinimumSize(gfx::Size(0, 0));
-  shell_surface->SetMaximumSize(gfx::Size(0, 0));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder()
+                           .SetMinimumSize(gfx::Size(0, 0))
+                           .SetMaximumSize(gfx::Size(0, 0))
+                           .BuildClientControlledShellSurface();
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 
   shell_surface->SetMinimumSize(gfx::Size(400, 400));
   shell_surface->SetMaximumSize(gfx::Size(0, 0));
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
   EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 
@@ -1284,17 +1100,9 @@
 // Test that when a shell surface is destroyed during its dragging, its window
 // delegate should be reset properly.
 TEST_F(ClientControlledShellSurfaceTest, CloseWindowWhenDraggingTest) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  const gfx::Rect original_bounds(0, 0, 256, 256);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetGeometry({0, 0, 256, 256})
+                           .BuildClientControlledShellSurface();
 
   // Press on the edge of the window and start dragging.
   gfx::Point touch_location(256, 150);
@@ -1362,16 +1170,13 @@
   UpdateDisplay("800x600");
   ash::Shell* shell = ash::Shell::Get();
   shell->tablet_mode_controller()->SetEnabledForTest(true);
-  std::unique_ptr<Surface> surface(new Surface());
-  const gfx::Size window_size(800, 552);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
+
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(window_size));
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder({800, 552})
+          .SetGeometry({0, 0, 800, 552})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ASSERT_TRUE(ash::WindowState::Get(window)->IsMaximized());
@@ -1499,21 +1304,16 @@
 TEST_F(ClientControlledShellSurfaceDisplayTest, MoveToAnotherDisplayByDrag) {
   UpdateDisplay("800x600,800x600");
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
 
-  gfx::Size window_size(200, 200);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
   gfx::Rect initial_bounds(-150, 10, 200, 200);
   shell_surface->SetBounds(primary_display.id(), initial_bounds);
   surface->Commit();
-  shell_surface->GetWidget()->Show();
 
   EXPECT_EQ(initial_bounds,
             shell_surface->GetWidget()->GetWindowBoundsInScreen());
@@ -1560,14 +1360,9 @@
        MoveToAnotherDisplayByShortcut) {
   UpdateDisplay("400x600,800x600*2");
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  gfx::Size window_size(200, 200);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
@@ -1615,15 +1410,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(0, 0, 64, 64));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(gfx::Rect(0, 0, 64, 64))
+                           .BuildClientControlledShellSurface();
 
   constexpr views::CaptionButtonIcon kAllButtons[] = {
       views::CAPTION_BUTTON_ICON_MINIMIZE,
@@ -1686,14 +1475,9 @@
 // should still be set (for overview mode, accessibility, etc.). When the debug
 // text is set, the window frame should paint it.
 TEST_F(ClientControlledShellSurfaceTest, SetExtraTitle) {
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(640, 64))));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 64})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   const std::u16string window_title(u"title");
   shell_surface->SetTitle(window_title);
@@ -1737,19 +1521,14 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, WideFrame) {
-  std::unique_ptr<Surface> surface(new Surface);
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 64, 64));
-  shell_surface->SetGeometry(gfx::Rect(100, 0, 64, 64));
-  shell_surface->SetMaximized();
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
-
+      exo::test::ShellSurfaceBuilder({64, 64})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetGeometry(gfx::Rect(100, 0, 64, 64))
+          .SetInputRegion(gfx::Rect(0, 0, 64, 64))
+          .SetFrame(SurfaceFrameType::NORMAL)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::Shelf* shelf = ash::Shelf::ForWindow(window);
   shelf->SetAlignment(ash::ShelfAlignment::kLeft);
@@ -1891,16 +1670,12 @@
 
 // Tests that a WideFrameView is created for an unparented ARC task and that the
 TEST_F(ClientControlledShellSurfaceTest, NoFrameOnModalContainer) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetUseSystemModalContainer()
+                           .SetGeometry(gfx::Rect(100, 0, 64, 64))
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(shell_surface->frame_enabled());
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
   surface->Commit();
@@ -1910,22 +1685,13 @@
 TEST_F(ClientControlledShellSurfaceTest,
        SetGeometryReparentsToDisplayOnFirstCommit) {
   UpdateDisplay("100x200,100x200");
-
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
   const auto* screen = display::Screen::GetScreen();
 
   {
-    std::unique_ptr<Surface> surface(new Surface);
-    auto shell_surface =
-        exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
     gfx::Rect geometry(16, 16, 32, 32);
-    shell_surface->SetGeometry(geometry);
-    surface->Attach(buffer.get());
-    surface->Commit();
+    auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                             .SetGeometry(geometry)
+                             .BuildClientControlledShellSurface();
     EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
     display::Display primary_display = screen->GetPrimaryDisplay();
@@ -1935,14 +1701,10 @@
   }
 
   {
-    std::unique_ptr<Surface> surface(new Surface);
-    auto shell_surface =
-        exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
     gfx::Rect geometry(116, 16, 32, 32);
-    shell_surface->SetGeometry(geometry);
-    surface->Attach(buffer.get());
-    surface->Commit();
+    auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                             .SetGeometry(geometry)
+                             .BuildClientControlledShellSurface();
     EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
     auto root_windows = ash::Shell::GetAllRootWindows();
@@ -1957,22 +1719,16 @@
 TEST_F(ClientControlledShellSurfaceTest, SetBoundsReparentsToDisplay) {
   UpdateDisplay("100x200,100x200");
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
   const auto* screen = display::Screen::GetScreen();
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  gfx::Rect geometry(16, 16, 32, 32);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(geometry)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display = screen->GetPrimaryDisplay();
-  gfx::Rect geometry(16, 16, 32, 32);
-
   // Move to primary display with bounds inside display.
   shell_surface->SetBounds(primary_display.id(), geometry);
-  surface->Attach(buffer.get());
   surface->Commit();
   EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
@@ -2043,9 +1799,12 @@
     {
       // Set display id, bounds origin, bounds size at the same time via
       // SetBounds method.
-      std::unique_ptr<Surface> surface(new Surface);
-      auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-          surface.get(), /*is_modal=*/false, default_scale_cancellation));
+      auto builder = exo::test::ShellSurfaceBuilder();
+      if (default_scale_cancellation)
+        builder.EnableDefaultScaleCancellation();
+      auto shell_surface =
+          builder.SetNoCommit().BuildClientControlledShellSurface();
+      auto* surface = shell_surface->root_surface();
 
       // When display doesn't change, scale stays the same
       shell_surface->SetScale(kOriginalScale);
@@ -2077,9 +1836,12 @@
       // method, and set bounds size separately.
       const auto bounds_to_set =
           default_scale_cancellation ? bounds_dp : bounds_px_for_4x;
-      std::unique_ptr<Surface> surface(new Surface);
-      auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-          surface.get(), /*is_modal=*/false, default_scale_cancellation));
+      auto builder = exo::test::ShellSurfaceBuilder();
+      if (default_scale_cancellation)
+        builder.EnableDefaultScaleCancellation();
+      auto shell_surface =
+          builder.SetNoCommit().BuildClientControlledShellSurface();
+      auto* surface = shell_surface->root_surface();
 
       shell_surface->SetScale(kOriginalScale);
       shell_surface->SetBoundsOrigin(primary_display_id,
@@ -2103,16 +1865,10 @@
   ash::ScreenOrientationController* controller =
       ash::Shell::Get()->screen_orientation_controller();
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  shell_surface->SetMaximized();
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
 
   shell_surface->SetOrientationLock(
       chromeos::OrientationType::kLandscapePrimary);
@@ -2128,17 +1884,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetClientAccessibilityId) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   EXPECT_FALSE(shell_surface->GetWidget());
   shell_surface->SetClientAccessibilityId(0);
-
-  surface->Attach(buffer.get());
   surface->Commit();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   EXPECT_EQ(0, *GetShellClientAccessibilityId(window));
@@ -2152,18 +1904,14 @@
 // Tests adjust bounds locally should also request remote client bounds update.
 TEST_F(ClientControlledShellSurfaceTest, AdjustBoundsLocally) {
   UpdateDisplay("800x600");
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  gfx::Rect client_bounds(900, 0, 200, 300);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(client_bounds)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  gfx::Rect client_bounds(900, 0, 200, 300);
-  shell_surface->SetGeometry(client_bounds);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   views::Widget* widget = shell_surface->GetWidget();
@@ -2179,16 +1927,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* window = shell_surface->GetWidget()->GetNativeWindow();
   auto* window_state = ash::WindowState::Get(window);
 
@@ -2209,15 +1952,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, PipWindowCannotBeActivated) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
   EXPECT_TRUE(shell_surface->GetWidget()->CanActivate());
@@ -2239,15 +1976,11 @@
 
 TEST_F(ClientControlledShellSurfaceDisplayTest,
        NoBoundsChangeEventInMinimized) {
-  gfx::Size buffer_size(100, 100);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Commit();
+  gfx::Rect client_bounds(100, 100);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
@@ -2303,18 +2036,17 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetPipWindowBoundsAnimates) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
   shell_surface->GetWidget()->Show();
+  auto* surface = shell_surface->root_surface();
+
+  // Making an extra commit may set the next bounds change animation type
+  // wrongly.
+  surface->Commit();
 
   ui::ScopedAnimationDurationScaleMode animation_scale_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
@@ -2327,18 +2059,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimate) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->GetTargetBounds());
@@ -2355,18 +2080,12 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        PipWindowDragDoesNotAnimateWithExtraCommit) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({client_bounds.size()})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Making an extra commit may set the next bounds change animation type
   // wrongly.
@@ -2395,19 +2114,10 @@
   EXPECT_FALSE(split_view_controller->InSplitViewMode());
 
   // Create a PIP window:
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto window_left = CreateTestWindow();
   auto window_right = CreateTestWindow();
 
@@ -2432,19 +2142,10 @@
   EXPECT_FALSE(split_view_controller->InSplitViewMode());
 
   // Create a PIP window:
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto window_left = CreateTestWindow();
   auto window_right = CreateTestWindow();
 
@@ -2478,42 +2179,29 @@
 };
 
 TEST_F(ClientControlledShellSurfaceTest, DoNotReplayWindowStateRequest) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
+      exo::test::ShellSurfaceBuilder({64, 64})
+          .SetWindowState(chromeos::WindowStateType::kMinimized)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   shell_surface->set_delegate(
       std::make_unique<NoStateChangeDelegate>(shell_surface.get()));
-
-  shell_surface->SetMinimized();
-  surface->Attach(buffer.get());
   surface->Commit();
 }
 
 TEST_F(ClientControlledShellSurfaceDisplayTest,
        RequestBoundsChangeOnceWithStateTransition) {
-  gfx::Size buffer_size(64, 64);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto* widget = shell_surface->GetWidget();
-  const gfx::Rect original_bounds(gfx::Point(20, 20), buffer_size);
-  shell_surface->SetGeometry(original_bounds);
-  widget->Restore();
-  surface->Commit();
+  constexpr gfx::Size buffer_size(64, 64);
+  constexpr gfx::Rect original_bounds({20, 20}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-
   shell_surface->SetPip();
   surface->Commit();
 
@@ -2523,25 +2211,17 @@
 TEST_F(ClientControlledShellSurfaceTest,
        DoNotSavePipBoundsAcrossMultiplePipTransition) {
   // Create a PIP window:
-  const gfx::Size content_size(100, 100);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(content_size));
-
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  constexpr gfx::Size buffer_size(100, 100);
+  constexpr gfx::Rect original_bounds({8, 10}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-
-  const gfx::Rect original_bounds(gfx::Point(8, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  shell_surface->SetPip();
-  surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 10, 100, 100), window->bounds());
-  shell_surface->GetWidget()->Show();
 
-  const gfx::Rect moved_bounds(gfx::Point(8, 20), content_size);
+  const gfx::Rect moved_bounds(gfx::Point(8, 20), buffer_size);
   shell_surface->SetGeometry(moved_bounds);
   surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 20, 100, 100), window->bounds());
@@ -2567,17 +2247,13 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        DoNotApplyCollisionDetectionWhileDragged) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(gfx::Point(8, 50), buffer_size));
-  shell_surface->SetPip();
-  surface->Commit();
+  constexpr gfx::Size buffer_size(256, 256);
+  constexpr gfx::Rect original_bounds({8, 50}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state = ash::WindowState::Get(window);
   EXPECT_EQ(gfx::Rect(8, 50, 256, 256), window->bounds());
@@ -2594,26 +2270,15 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, EnteringPipSavesPipSnapFraction) {
-  const gfx::Size content_size(100, 100);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(content_size));
-
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  constexpr gfx::Size buffer_size(100, 100);
+  constexpr gfx::Rect original_bounds({8, 50}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state = ash::WindowState::Get(window);
-
-  // Put the PIP window off the top edge as snap fraction has more likely to
-  // have an error vertically.
-  const gfx::Rect original_bounds(gfx::Point(8, 50), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  shell_surface->SetPip();
-  surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 50, 100, 100), window->bounds());
-  shell_surface->GetWidget()->Show();
 
   // Ensure the correct value is saved to pip snap fraction.
   EXPECT_TRUE(ash::PipPositioner::HasSnapFraction(window_state));
@@ -2623,9 +2288,9 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        ShadowBoundsChangedIsResetAfterCommit) {
-  auto surface = std::make_unique<Surface>();
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+      exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   surface->SetFrame(SurfaceFrameType::SHADOW);
   shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
   EXPECT_TRUE(shell_surface->get_shadow_bounds_changed_for_testing());
@@ -2652,16 +2317,13 @@
 TEST_F(ClientControlledShellSurfaceScaleTest, ScaleSetOnInitialCommit) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({20, 20})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2673,21 +2335,18 @@
        DeferScaleCommitForRestoredWindow) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({20, 20})
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  shell_surface->SetRestored();
-  surface->Attach(buffer.get());
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2717,20 +2376,18 @@
        CommitScaleChangeImmediatelyForMaximizedWindow) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({20, 20})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
   surface->Commit();
 
@@ -2751,21 +2408,18 @@
   EnableTabletMode(true);
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({20, 20})
+          .SetWindowState(chromeos::WindowStateType::kSecondarySnapped)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
-
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
-  shell_surface->SetSnappedToSecondary();
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2791,13 +2445,10 @@
 TEST_F(ClientControlledShellSurfaceTest, SnappedClientBounds) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Clear insets so that it won't affects the bounds.
   shell_surface->SetSystemUiVisibility(true);
@@ -2807,8 +2458,6 @@
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-
-  surface->Attach(buffer.get());
   surface->Commit();
   views::Widget* widget = shell_surface->GetWidget();
   aura::Window* window = widget->GetNativeWindow();
@@ -2854,29 +2503,31 @@
 // The shell surface with resize lock on should be unresizable.
 TEST_F(ClientControlledShellSurfaceTest,
        ShellSurfaceWithResizeLockOnIsUnresizable) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+
+  EXPECT_TRUE(shell_surface->CanResize());
+
+  shell_surface->SetResizeLockType(
+      ash::ArcResizeLockType::RESIZE_DISABLED_TOGGLABLE);
   surface->Commit();
+  EXPECT_FALSE(shell_surface->CanResize());
+
+  shell_surface->SetResizeLockType(
+      ash::ArcResizeLockType::RESIZE_ENABLED_TOGGLABLE);
+  surface->Commit();
+  EXPECT_TRUE(shell_surface->CanResize());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, OverlayShadowBounds) {
-  gfx::Size buffer_size(1, 1);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  gfx::Rect initial_bounds(150, 10, 200, 200);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({1, 1})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_bounds(150, 10, 200, 200);
   shell_surface->SetBounds(primary_display.id(), initial_bounds);
   shell_surface->OnSetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
@@ -2899,18 +2550,12 @@
 // WideFrameView follows its respective surface when it is eventually parented.
 // See crbug.com/1223135.
 TEST_F(ClientControlledShellSurfaceTest, WideframeForUnparentedTasks) {
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Create a non-wide frame shell surface.
-  auto desktop_buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 64, 64));
-  shell_surface->SetGeometry(gfx::Rect(100, 0, 64, 64));
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(gfx::Rect(100, 0, 64, 64))
+                           .SetInputRegion(gfx::Rect(0, 0, 64, 64))
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* wide_frame = shell_surface->wide_frame_for_test();
   ASSERT_FALSE(wide_frame);
 
@@ -2945,10 +2590,8 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        InitializeWindowStateGrantsPermissionToActivate) {
-  auto surface = std::make_unique<Surface>();
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   auto* permission = window->GetProperty(kPermissionKey);
diff --git a/components/exo/server/arc_overlay_manager_unittest.cc b/components/exo/server/arc_overlay_manager_unittest.cc
index 59aef6f..cac7e4a 100644
--- a/components/exo/server/arc_overlay_manager_unittest.cc
+++ b/components/exo/server/arc_overlay_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include "components/exo/sub_surface.h"
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/base/class_property.h"
 
@@ -20,23 +21,16 @@
 };
 
 TEST_F(ArcOverlayManagerTest, Basic) {
-  gfx::Size buffer_size(256, 256);
-
-  std::unique_ptr<Surface> surface1(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface1.get()));
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface1 = shell_surface->root_surface();
 
   // Create Widget
   shell_surface->SetSystemUiVisibility(false);
 
-  std::unique_ptr<Surface> surface2(new Surface);
-  auto sub_surface =
-      std::make_unique<SubSurface>(surface2.get(), surface1.get());
-
-  std::unique_ptr<Buffer> buffer2(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  surface2->Attach(buffer2.get());
+  auto* surface2 =
+      test::ShellSurfaceBuilder::AddChildSurface(surface1, {0, 0, 128, 128});
 
   // Make
   surface2->Commit();
diff --git a/components/exo/shell_surface_util_unittest.cc b/components/exo/shell_surface_util_unittest.cc
index 8329554..d492bf54 100644
--- a/components/exo/shell_surface_util_unittest.cc
+++ b/components/exo/shell_surface_util_unittest.cc
@@ -78,23 +78,18 @@
                               shell_surface->GetWidget()->GetNativeWindow()));
 }
 
+// No explicit verifications are needed for this test as this test just tries to
+// catch potential crashes.
 TEST_F(ShellSurfaceUtilTest, ClientControlledTargetForKeyboardFocus) {
   Display display;
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
   shell_surface->set_delegate(
       std::make_unique<test::ClientControlledShellSurfaceDelegate>(
           shell_surface.get(), true));
   shell_surface->SetMinimized();
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   shell_surface->GetWidget()->Hide();
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index c92e2c3..ed53413 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -136,27 +136,6 @@
                               gpu::kNullSurfaceHandle, nullptr);
 }
 
-std::unique_ptr<ClientControlledShellSurface>
-ExoTestHelper::CreateClientControlledShellSurface(
-    Surface* surface,
-    bool is_modal,
-    bool default_scale_cancellation) {
-  int container = is_modal ? ash::kShellWindowId_SystemModalContainer
-                           : ash::desks_util::GetActiveDeskContainerId();
-  auto shell_surface = Display().CreateOrGetClientControlledShellSurface(
-      surface, container,
-      WMHelper::GetInstance()->GetDefaultDeviceScaleFactor(),
-      default_scale_cancellation);
-  shell_surface->SetApplicationId("arc");
-  // ARC's default min size is non-empty.
-  shell_surface->SetMinimumSize(gfx::Size(1, 1));
-  shell_surface->set_delegate(
-      std::make_unique<ClientControlledShellSurfaceDelegate>(
-          shell_surface.get()));
-
-  return shell_surface;
-}
-
 std::unique_ptr<InputMethodSurface> ExoTestHelper::CreateInputMethodSurface(
     Surface* surface,
     InputMethodSurfaceManager* surface_manager,
diff --git a/components/exo/test/shell_surface_builder.cc b/components/exo/test/shell_surface_builder.cc
index cd03f31..6eb8596 100644
--- a/components/exo/test/shell_surface_builder.cc
+++ b/components/exo/test/shell_surface_builder.cc
@@ -6,6 +6,7 @@
 
 #include <tuple>
 
+#include "ash/constants/app_types.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "components/exo/buffer.h"
@@ -15,6 +16,7 @@
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/xdg_shell_surface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 
 #include "base/logging.h"
@@ -34,7 +36,7 @@
                       absl::optional<gfx::BufferFormat> buffer_format) {
     auto surface = std::make_unique<exo::Surface>();
     std::unique_ptr<exo::Buffer> buffer;
-    if (buffer_format) {
+    if (!size.IsEmpty() && buffer_format) {
       buffer = std::make_unique<exo::Buffer>(
           aura::Env::GetInstance()
               ->context_factory()
@@ -135,6 +137,12 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::EnableSystemModal() {
+  DCHECK(!built_);
+  system_modal_ = true;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::SetNoCommit() {
   DCHECK(!built_);
   commit_on_build_ = false;
@@ -161,6 +169,33 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetGeometry(
+    const gfx::Rect& geometry) {
+  DCHECK(!built_);
+  geometry_ = geometry;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetInputRegion(
+    const cc::Region& region) {
+  DCHECK(!built_);
+  input_region_ = region;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetFrame(SurfaceFrameType type) {
+  DCHECK(!built_);
+  type_ = type;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetApplicationId(
+    const std::string& application_id) {
+  DCHECK(!built_);
+  application_id_ = application_id;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::SetDisableMovement() {
   DCHECK(!built_);
   disable_movement_ = true;
@@ -185,12 +220,26 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetWindowState(
+    chromeos::WindowStateType window_state) {
+  DCHECK(!built_);
+  window_state_ = window_state;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::EnableDefaultScaleCancellation() {
   DCHECK(!built_);
   default_scale_cancellation_ = true;
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetDelegate(
+    std::unique_ptr<ClientControlledShellSurface::Delegate> delegate) {
+  DCHECK(!built_);
+  delegate_ = std::move(delegate);
+  return *this;
+}
+
 // static
 void ShellSurfaceBuilder::DestroyRootSurface(ShellSurfaceBase* shell_surface) {
   Holder* holder =
@@ -244,21 +293,62 @@
   shell_surface->host_window()->SetProperty(kBuilderResourceHolderKey, holder);
 
   // Set the properties specific to ClientControlledShellSurface.
-  shell_surface->SetApplicationId("arc");
+  shell_surface->SetApplicationId(!application_id_.empty()
+                                      ? application_id_.c_str()
+                                      : "org.chromium.arc.1");
   // ARC's default min size is non-empty.
   if (!min_size_.has_value())
     shell_surface->SetMinimumSize(gfx::Size(1, 1));
-  shell_surface->set_delegate(
-      std::make_unique<ClientControlledShellSurfaceDelegate>(
-          shell_surface.get()));
+  if (delegate_) {
+    shell_surface->set_delegate(std::move(delegate_));
+  } else {
+    shell_surface->set_delegate(
+        std::make_unique<ClientControlledShellSurfaceDelegate>(
+            shell_surface.get()));
+  }
+  if (window_state_.has_value()) {
+    switch (window_state_.value()) {
+      case chromeos::WindowStateType::kDefault:
+      case chromeos::WindowStateType::kNormal:
+        shell_surface->SetRestored();
+        break;
+      case chromeos::WindowStateType::kMaximized:
+        shell_surface->SetMaximized();
+        break;
+      case chromeos::WindowStateType::kMinimized:
+        shell_surface->SetMinimized();
+        break;
+      case chromeos::WindowStateType::kFullscreen:
+        shell_surface->SetFullscreen(/*fullscreen=*/true);
+        break;
+      case chromeos::WindowStateType::kPrimarySnapped:
+        shell_surface->SetSnappedToPrimary();
+        break;
+      case chromeos::WindowStateType::kSecondarySnapped:
+        shell_surface->SetSnappedToSecondary();
+        break;
+      case chromeos::WindowStateType::kPip:
+        shell_surface->SetPip();
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
 
   SetCommonPropertiesAndCommitIfNecessary(shell_surface.get());
 
+  // The widget becomes available after the first commit.
+  if (shell_surface->GetWidget()) {
+    shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
+        aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
+  }
+
   return shell_surface;
 }
 
 bool ShellSurfaceBuilder::isConfigurationValidForShellSurface() {
-  return !default_scale_cancellation_;
+  return !default_scale_cancellation_ && !window_state_.has_value() &&
+         !delegate_;
 }
 
 bool ShellSurfaceBuilder::
@@ -277,6 +367,21 @@
   if (min_size_.has_value())
     shell_surface->SetMinimumSize(min_size_.value());
 
+  if (geometry_.has_value())
+    shell_surface->SetGeometry(geometry_.value());
+
+  if (input_region_.has_value()) {
+    shell_surface->root_surface()->SetInputRegion(input_region_.value());
+  }
+
+  if (type_.has_value()) {
+    shell_surface->root_surface()->SetFrame(type_.value());
+  }
+
+  if (system_modal_) {
+    shell_surface->SetSystemModal(true);
+  }
+
   if (commit_on_build_) {
     shell_surface->root_surface()->Commit();
     if (centered_)
diff --git a/components/exo/test/shell_surface_builder.h b/components/exo/test/shell_surface_builder.h
index c4e8580..dd89dc0 100644
--- a/components/exo/test/shell_surface_builder.h
+++ b/components/exo/test/shell_surface_builder.h
@@ -7,6 +7,8 @@
 
 #include <memory>
 
+#include "cc/base/region.h"
+#include "components/exo/client_controlled_shell_surface.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/class_property.h"
 #include "ui/gfx/buffer_types.h"
@@ -27,7 +29,7 @@
 // destroyed when the shell surface is destroyed.
 class ShellSurfaceBuilder {
  public:
-  ShellSurfaceBuilder(const gfx::Size& buffer_size);
+  explicit ShellSurfaceBuilder(const gfx::Size& buffer_size = {0, 0});
   ShellSurfaceBuilder(ShellSurfaceBuilder& other) = delete;
   ShellSurfaceBuilder& operator=(ShellSurfaceBuilder& other) = delete;
   ~ShellSurfaceBuilder();
@@ -37,10 +39,17 @@
   ShellSurfaceBuilder& SetRootBufferFormat(gfx::BufferFormat buffer_format);
   ShellSurfaceBuilder& SetOrigin(const gfx::Point& origin);
   ShellSurfaceBuilder& SetUseSystemModalContainer();
+  ShellSurfaceBuilder& EnableSystemModal();
+  // When set true, some properties such as kAppType may not be set by this
+  // builder as they need the widget created in the commit process.
   ShellSurfaceBuilder& SetNoCommit();
   ShellSurfaceBuilder& SetCanMinimize(bool can_minimize);
   ShellSurfaceBuilder& SetMaximumSize(const gfx::Size& size);
   ShellSurfaceBuilder& SetMinimumSize(const gfx::Size& size);
+  ShellSurfaceBuilder& SetGeometry(const gfx::Rect& geometry);
+  ShellSurfaceBuilder& SetInputRegion(const cc::Region& region);
+  ShellSurfaceBuilder& SetFrame(SurfaceFrameType type);
+  ShellSurfaceBuilder& SetApplicationId(const std::string& application_id);
   ShellSurfaceBuilder& SetDisableMovement();
   ShellSurfaceBuilder& SetCentered();
 
@@ -49,7 +58,10 @@
   ShellSurfaceBuilder& SetAsPopup();
 
   // Sets parameters defined in ClientControlledShellSurface.
+  ShellSurfaceBuilder& SetWindowState(chromeos::WindowStateType window_state);
   ShellSurfaceBuilder& EnableDefaultScaleCancellation();
+  ShellSurfaceBuilder& SetDelegate(
+      std::unique_ptr<ClientControlledShellSurface::Delegate> delegate);
 
   // Must be called only once for either of the below and the object cannot
   // be used to create multiple windows.
@@ -74,7 +86,12 @@
   gfx::Point origin_;
   absl::optional<gfx::Size> max_size_;
   absl::optional<gfx::Size> min_size_;
+  absl::optional<gfx::Rect> geometry_;
+  absl::optional<cc::Region> input_region_;
+  absl::optional<SurfaceFrameType> type_;
+  std::string application_id_;
   bool use_system_modal_container_ = false;
+  bool system_modal_ = false;
   bool commit_on_build_ = true;
   bool can_minimize_ = true;
   bool disable_movement_ = false;
@@ -86,7 +103,9 @@
   bool popup_ = false;
 
   // ClientControlledShellSurface-specific parameters.
+  absl::optional<chromeos::WindowStateType> window_state_;
   bool default_scale_cancellation_ = false;
+  std::unique_ptr<ClientControlledShellSurface::Delegate> delegate_;
 };
 
 }  // namespace test
diff --git a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
index 22201aae..16cdd7e 100644
--- a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
+++ b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
@@ -16,7 +16,9 @@
 #include "base/bind.h"
 #include "base/posix/unix_domain_socket.h"
 #include "components/exo/display.h"
+#include "components/exo/shell_surface.h"
 #include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wayland/server_util.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -71,6 +73,9 @@
     wl_shell_resource_.reset(wl_resource_create(wl_client_.get(),
                                                 &zcr_remote_shell_v2_interface,
                                                 /*version=*/1, /*id=*/0));
+    wl_remote_surface_resource_.reset(
+        wl_resource_create(wl_client(), &zcr_remote_surface_v2_interface,
+                           /*version=*/1, /*id=*/0));
 
     display_ = std::make_unique<Display>();
     shell_ = std::make_unique<WaylandRemoteShell>(
@@ -91,6 +96,11 @@
     ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
   }
 
+  std::unique_ptr<ClientControlledShellSurface::Delegate> CreateDelegate() {
+    return shell()->CreateShellSurfaceDelegate(
+        wl_remote_surface_resource_.get());
+  }
+
   void ResetEventRecords() {
     remote_shell_event_sequence_.clear();
     remote_shell_requested_bounds_changes_.clear();
@@ -100,6 +110,8 @@
 
   wl_client* wl_client() { return wl_client_.get(); }
 
+  wl_resource* wl_remote_surface() { return wl_remote_surface_resource_.get(); }
+
   static std::vector<RemoteShellEventType> remote_shell_event_sequence() {
     return remote_shell_event_sequence_;
   }
@@ -118,6 +130,7 @@
   ScopedWlDisplay wl_display_;
   ScopedWlClient wl_client_;
   ScopedWlResource wl_shell_resource_;
+  ScopedWlResource wl_remote_surface_resource_;
 
   std::unique_ptr<WaylandRemoteShell> shell_;
 
@@ -212,22 +225,10 @@
 // Test that all bounds change requests are deferred while the tablet transition
 // is happening until it's finished.
 TEST_F(WaylandRemoteShellTest, TabletTransition) {
-  // Setup buffer/surface/window.
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetDelegate(CreateDelegate())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* const widget = shell_surface->GetWidget();
   auto* const window = widget->GetNativeWindow();
 
@@ -255,27 +256,18 @@
 // proper values and in proper order when display zoom happens. A bounds change
 // event must be triggered only for PIP.
 TEST_F(WaylandRemoteShellTest, DisplayZoom) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
+  // Test a restored window first.
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  auto* const window = shell_surface->GetWidget()->GetNativeWindow();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetDelegate(CreateDelegate())
+          .SetWindowState(chromeos::WindowStateType::kNormal)
+          .SetGeometry({100, 100, kDefaultWindowLength, kDefaultWindowLength})
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+  auto* window = shell_surface->GetWidget()->GetNativeWindow();
   const display::Display& display =
       display::Screen::GetScreen()->GetDisplayNearestWindow(window);
 
-  // Test a restored window.
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
   ResetEventRecords();
   ash::Shell::Get()->display_manager()->ZoomDisplay(display.id(), /*up=*/true);
   task_environment()->RunUntilIdle();
@@ -326,27 +318,18 @@
 // proper values and in proper order when display rotation happens. A bounds
 // change event must be triggered only for PIP.
 TEST_F(WaylandRemoteShellTest, DisplayRotation) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
+  // Test a restored window first.
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  auto* const window = shell_surface->GetWidget()->GetNativeWindow();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetDelegate(CreateDelegate())
+          .SetWindowState(chromeos::WindowStateType::kNormal)
+          .SetGeometry({100, 100, kDefaultWindowLength, kDefaultWindowLength})
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+  auto* window = shell_surface->GetWidget()->GetNativeWindow();
   const display::Display& display =
       display::Screen::GetScreen()->GetDisplayNearestWindow(window);
 
-  // Test a restored window.
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
   ResetEventRecords();
   ash::Shell::Get()->display_manager()->SetDisplayRotation(
       display.id(), display::Display::ROTATE_90,
@@ -411,21 +394,11 @@
 // and workspace info events are triggered with proper values and in
 // proper order.
 TEST_F(WaylandRemoteShellTest, DisplayRemovalAddition) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder(
+                           {kDefaultWindowLength, kDefaultWindowLength})
+                           .SetDelegate(CreateDelegate())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Add secondary display with a different scale factor.
   UpdateDisplay("800x600,800x600*2");
@@ -496,31 +469,25 @@
 // Test that the desktop focus state event is called with the proper value in
 // response to window focus change.
 TEST_F(WaylandRemoteShellTest, DesktopFocusState) {
-  // Setup buffer/surface/window.
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  SetSurfaceResource(surface.get(), wl_res.get());
-
-  surface->Attach(buffer.get());
+  auto client_controlled_shell_surface =
+      exo::test::ShellSurfaceBuilder(
+          {kDefaultWindowLength, kDefaultWindowLength})
+          .SetDelegate(CreateDelegate())
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = client_controlled_shell_surface->root_surface();
+  SetSurfaceResource(surface, wl_remote_surface());
   surface->Commit();
   EXPECT_EQ(last_desktop_focus_state(), 2);
 
-  shell_surface->SetMinimized();
+  client_controlled_shell_surface->SetMinimized();
   surface->Commit();
   EXPECT_EQ(last_desktop_focus_state(), 1);
 
-  auto* other_client_window =
-      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
+  auto shell_surface = exo::test::ShellSurfaceBuilder(
+                           {kDefaultWindowLength, kDefaultWindowLength})
+                           .BuildShellSurface();
+  auto* other_client_window = shell_surface->GetWidget()->GetNativeWindow();
   other_client_window->Show();
   other_client_window->Focus();
   EXPECT_EQ(last_desktop_focus_state(), 3);
diff --git a/components/history_clusters/history_clusters_internals/resources/BUILD.gn b/components/history_clusters/history_clusters_internals/resources/BUILD.gn
index 195b4ca..9e73b33 100644
--- a/components/history_clusters/history_clusters_internals/resources/BUILD.gn
+++ b/components/history_clusters/history_clusters_internals/resources/BUILD.gn
@@ -24,15 +24,6 @@
   output_dir = "$root_gen_dir/components"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "history_clusters_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [ "history_clusters_internals.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 copy("copy_ts") {
   sources = [
     "history_clusters_internals.ts",
@@ -63,3 +54,13 @@
     ":copy_ts",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "history_clusters_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [ "history_clusters_internals.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/components/image_fetcher/BUILD.gn b/components/image_fetcher/BUILD.gn
index e107b046..42f212425 100644
--- a/components/image_fetcher/BUILD.gn
+++ b/components/image_fetcher/BUILD.gn
@@ -72,6 +72,7 @@
     "//third_party/junit",
     "//third_party/mockito:mockito_java",
     "//url:gurl_java",
+    "//url:gurl_junit_shadows",
     "//url:gurl_junit_test_support",
   ]
 }
diff --git a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/CachedImageFetcher.java b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/CachedImageFetcher.java
index 6eca0d579..e99255c3 100644
--- a/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/CachedImageFetcher.java
+++ b/components/image_fetcher/android/java/src/org/chromium/components/image_fetcher/CachedImageFetcher.java
@@ -137,7 +137,9 @@
             Bitmap cachedBitmap, long startTimeMillis) {
         if (cachedBitmap != null) {
             // In case the image's dimensions on disk don't match the desired dimensions.
-            cachedBitmap = ImageFetcher.resizeImage(cachedBitmap, params.width, params.height);
+            if (params.shouldResize) {
+                cachedBitmap = ImageFetcher.resizeImage(cachedBitmap, params.width, params.height);
+            }
             callback.onResult(cachedBitmap);
             reportEvent(params.clientName, ImageFetcherEvent.JAVA_DISK_CACHE_HIT);
             getImageFetcherBridge().reportCacheHitTime(params.clientName, startTimeMillis);
diff --git a/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/CachedImageFetcherTest.java b/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/CachedImageFetcherTest.java
index 4697933..97f5b29 100644
--- a/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/CachedImageFetcherTest.java
+++ b/components/image_fetcher/android/junit/src/org/chromium/components/image_fetcher/CachedImageFetcherTest.java
@@ -30,6 +30,9 @@
 import org.chromium.base.task.TaskTraits;
 import org.chromium.base.task.test.ShadowPostTask;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.url.GURL;
+import org.chromium.url.JUnitTestGURLs;
+import org.chromium.url.ShadowGURL;
 
 import jp.tomorrowkey.android.gifplayer.BaseGifImage;
 
@@ -37,10 +40,10 @@
  * Unit tests for CachedImageFetcher.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, shadows = {ShadowPostTask.class})
+@Config(manifest = Config.NONE, shadows = {ShadowGURL.class, ShadowPostTask.class})
 public class CachedImageFetcherTest {
     private static final String UMA_CLIENT_NAME = "TestUmaClient";
-    private static final String URL = "http://google.com/test.png";
+    private static final String URL = JUnitTestGURLs.RED_1;
     private static final String PATH = "test/path/cache/test.png";
     private static final int WIDTH_PX = 10;
     private static final int HEIGHT_PX = 20;
@@ -106,13 +109,18 @@
     }
 
     @Test
-    public void testFetchImage_fileFoundOnDisk() {
+    public void testFetchImage_fileFoundOnDisk_imageNotResized() {
         doReturn(mBitmap).when(mImageLoader).tryToLoadImageFromDisk(PATH);
 
-        ImageFetcher.Params params =
-                ImageFetcher.Params.create(URL, UMA_CLIENT_NAME, WIDTH_PX, HEIGHT_PX);
+        ImageFetcher.Params params = ImageFetcher.Params.createNoResizing(
+                new GURL(URL), UMA_CLIENT_NAME, WIDTH_PX + 1, HEIGHT_PX + 1);
         mCachedImageFetcher.fetchImage(params, mBitmapCallback);
-        verify(mBitmapCallback).onResult(mBitmap);
+
+        // Unresized bitmap should be returned.
+        ArgumentCaptor<Bitmap> bitmapCaptor = ArgumentCaptor.forClass(Bitmap.class);
+        verify(mBitmapCallback).onResult(bitmapCaptor.capture());
+        Assert.assertEquals(mBitmap, bitmapCaptor.getValue());
+
         verify(mBridge, never())
                 .fetchImage(eq(ImageFetcherConfig.DISK_CACHE_ONLY), eq(params), any());
         verify(mBridge).reportEvent(UMA_CLIENT_NAME, ImageFetcherEvent.JAVA_DISK_CACHE_HIT);
diff --git a/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn b/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
index 8de928f3..093df04e 100644
--- a/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
+++ b/components/optimization_guide/optimization_guide_internals/resources/BUILD.gn
@@ -24,15 +24,6 @@
   output_dir = "$root_gen_dir/components"
 }
 
-generate_grd("build_grd") {
-  grd_prefix = "optimization_guide_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  input_files = [ "optimization_guide_internals.html" ]
-  input_files_base_dir = rebase_path(".", "//")
-}
-
 copy("copy_ts") {
   sources = [
     "optimization_guide_internals.ts",
@@ -66,3 +57,13 @@
     ":copy_ts",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "optimization_guide_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  input_files = [ "optimization_guide_internals.html" ]
+  input_files_base_dir = rebase_path(".", "//")
+}
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index f32dbb7d..21c14d28 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -168,6 +168,8 @@
 PasswordForm GetTestBlocklistedAndroidCredentials(const char* signon_realm) {
   PasswordForm form = GetTestAndroidCredentials(signon_realm);
   form.blocked_by_user = true;
+  form.username_value.clear();
+  form.password_value.clear();
   return form;
 }
 
diff --git a/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index a1dbd3c..1d24509c 100644
--- a/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -1629,24 +1629,6 @@
   EXPECT_EQ(PasswordForm::Scheme::kHtml, synthesized.scheme);
 }
 
-TEST_P(CredentialManagerImplTest, GetBlockedPasswordCredential) {
-  PasswordForm blocked_form;
-  blocked_form.blocked_by_user = true;
-  blocked_form.url = form_.url;
-  blocked_form.signon_realm = blocked_form.url.spec();
-  // Deliberately use a wrong format with a non-empty username to simulate a
-  // leak. See https://crbug.com/817754.
-  blocked_form.username_value = u"Username";
-  store_->AddLogin(blocked_form);
-
-  EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _)).Times(0);
-  EXPECT_CALL(*client_, NotifyUserAutoSigninPtr()).Times(0);
-
-  std::vector<GURL> federations;
-  ExpectCredentialType(CredentialMediationRequirement::kOptional, true,
-                       federations, CredentialType::CREDENTIAL_TYPE_EMPTY);
-}
-
 TEST_P(CredentialManagerImplTest, BlockedPasswordCredential) {
   EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(_));
 
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 044f68fb..a077578 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -109,6 +109,9 @@
 
 void PasswordStore::AddLogin(const PasswordForm& form) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  // TODO(crbug.com/1324588): Replace by DCHECK
+  CHECK(!form.blocked_by_user ||
+        (form.username_value.empty() && form.password_value.empty()));
   if (!backend_)
     return;  // Once the shutdown started, ignore new requests.
   backend_->AddLoginAsync(
@@ -120,6 +123,9 @@
 
 void PasswordStore::UpdateLogin(const PasswordForm& form) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  // TODO(crbug.com/1324588): Replace by DCHECK
+  CHECK(!form.blocked_by_user ||
+        (form.username_value.empty() && form.password_value.empty()));
   if (!backend_)
     return;  // Once the shutdown started, ignore new requests.
   backend_->UpdateLoginAsync(
diff --git a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
index 6daf898..4707b4d 100644
--- a/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
+++ b/components/password_manager/core/browser/store_metrics_reporter_unittest.cc
@@ -84,6 +84,7 @@
 
   password_form.url = GURL("https://fifth.example.com/");
   password_form.signon_realm = "https://fifth.example.com/";
+  password_form.username_value = u"";
   password_form.password_value = u"";
   password_form.blocked_by_user = true;
   store->AddLogin(password_form);
@@ -107,6 +108,8 @@
 
   password_form.url = GURL("http://rsolomakhin.github.io/autofill/");
   password_form.signon_realm = "http://rsolomakhin.github.io/";
+  password_form.username_value = u"";
+  password_form.password_value = u"";
   password_form.blocked_by_user = true;
   store->AddLogin(password_form);
 
@@ -695,9 +698,8 @@
   password_form.username_value = u"username_1";
   profile_store->AddLogin(password_form);
   password_form.blocked_by_user = true;
-  password_form.username_value = u"username_2";
-  profile_store->AddLogin(password_form);
-  password_form.username_value = u"username_3";
+  password_form.username_value = u"";
+  password_form.password_value = u"";
   profile_store->AddLogin(password_form);
 
   base::HistogramTester histogram_tester;
diff --git a/components/sync/driver/resources/BUILD.gn b/components/sync/driver/resources/BUILD.gn
index d3f25b2..97bb4c0 100644
--- a/components/sync/driver/resources/BUILD.gn
+++ b/components/sync/driver/resources/BUILD.gn
@@ -19,12 +19,11 @@
   ]
 }
 
-#TODO(crbug.com/986001): Migrate the files below to TypeScript.
 preprocessed_files = [ "sync_index.ts" ]
 non_preprocessed_files = [
-  "about.js",
+  "about.ts",
   "chrome_sync.ts",
-  "data.js",
+  "data.ts",
   "invalidations.ts",
   "search.ts",
   "sync_log.ts",
@@ -77,10 +76,9 @@
     "traffic_log.css",
   ]
   input_files_base_dir = rebase_path("./", "//")
-  manifest_files = [
-    "$target_gen_dir/css_manifest.json",
-    "$target_gen_dir/tsconfig.manifest",
-  ]
+  manifest_files =
+      [ "$target_gen_dir/css_manifest.json" ] +
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
 
 grit("resources") {
diff --git a/components/sync/driver/resources/about.js b/components/sync/driver/resources/about.js
deleted file mode 100644
index a0343a79..0000000
--- a/components/sync/driver/resources/about.js
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import 'chrome://resources/js/jstemplate_compiled.js';
-
-import {addWebUIListener, removeWebUIListener} from 'chrome://resources/js/cr.m.js';
-import {$} from 'chrome://resources/js/util.m.js';
-
-import {requestDataAndRegisterForUpdates, requestStart, requestStopClearData, requestStopKeepData, setIncludeSpecifics, triggerRefresh} from './chrome_sync.js';
-
-// Contains the latest snapshot of sync about info.
-export let aboutInfo = {};
-
-// For tests
-window.getAboutInfoForTest = function() {
-  return aboutInfo;
-};
-
-let aboutInfoListener = null;
-let entityCountsUpdatedListener = null;
-
-function highlightIfChanged(node, oldVal, newVal) {
-  function clearHighlight() {
-    this.removeAttribute('highlighted');
-  }
-
-  const oldStr = oldVal.toString();
-  const newStr = newVal.toString();
-  if (oldStr !== '' && oldStr !== newStr) {
-    // Note the addListener function does not end up creating duplicate
-    // listeners.  There can be only one listener per event at a time.
-    // Reference: https://developer.mozilla.org/en/DOM/element.addEventListener
-    node.addEventListener('webkitAnimationEnd', clearHighlight, false);
-    node.setAttribute('highlighted', '');
-  }
-}
-
-function refreshAboutInfo(newAboutInfo) {
-  aboutInfo = newAboutInfo;
-  const aboutInfoDiv = $('about-info');
-  jstProcess(new JsEvalContext(aboutInfo), aboutInfoDiv);
-}
-
-function onEntityCountsUpdatedEvent(response) {
-  if (!aboutInfo.type_status) {
-    return;
-  }
-  for (const count of response.entityCounts) {
-    const typeStatusRow =
-        aboutInfo.type_status.find(row => row.name === count.modelType);
-    if (typeStatusRow) {
-      typeStatusRow.num_entries = count.entities;
-      typeStatusRow.num_live = count.nonTombstoneEntities;
-    }
-  }
-  jstProcess(
-      new JsEvalContext({type_status: aboutInfo.type_status}), $('typeInfo'));
-}
-
-/**
- * Helper to determine if an element is scrolled to its bottom limit.
- * @param {Element} elem element to check
- * @return {boolean} true if the element is scrolled to the bottom
- */
-function isScrolledToBottom(elem) {
-  return elem.scrollHeight - elem.scrollTop === elem.clientHeight;
-}
-
-/**
- * Helper to scroll an element to its bottom limit.
- * @param {Element} elem element to be scrolled
- */
-function scrollToBottom(elem) {
-  elem.scrollTop = elem.scrollHeight - elem.clientHeight;
-}
-
-/** Container for accumulated sync protocol events. */
-const protocolEvents = [];
-
-/** We may receive re-delivered events.  Keep a record of ones we've seen. */
-const knownEventTimestamps = {};
-
-/**
- * Callback for incoming protocol events.
- * @param {Object} response The protocol event response.
- */
-function onReceivedProtocolEvent(response) {
-  // Return early if we've seen this event before.  Assumes that timestamps
-  // are sufficiently high resolution to uniquely identify an event.
-  if (knownEventTimestamps.hasOwnProperty(response.time)) {
-    return;
-  }
-
-  knownEventTimestamps[response.time] = true;
-  protocolEvents.push(response);
-
-  const trafficContainer = $('traffic-event-container');
-
-  // Scroll to the bottom if we were already at the bottom.  Otherwise, leave
-  // the scrollbar alone.
-  const shouldScrollDown = isScrolledToBottom(trafficContainer);
-
-  const context = new JsEvalContext({events: protocolEvents});
-  jstProcess(context, trafficContainer);
-
-  if (shouldScrollDown) {
-    scrollToBottom(trafficContainer);
-  }
-}
-
-/**
- * Initializes state and callbacks for the protocol event log UI.
- */
-function initProtocolEventLog() {
-  const includeSpecificsCheckbox = $('capture-specifics');
-  includeSpecificsCheckbox.addEventListener('change', function(event) {
-    setIncludeSpecifics(includeSpecificsCheckbox.checked);
-  });
-
-  addWebUIListener('onProtocolEvent', onReceivedProtocolEvent);
-
-  // Make the prototype jscontent element disappear.
-  jstProcess({}, $('traffic-event-container'));
-
-  const triggerRefreshButton = $('trigger-refresh');
-  triggerRefreshButton.addEventListener('click', function(event) {
-    triggerRefresh();
-  });
-}
-
-/**
- * Initializes listeners for status dump and import UI.
- */
-function initStatusDumpButton() {
-  $('status-data').hidden = true;
-
-  const dumpStatusButton = $('dump-status');
-  dumpStatusButton.addEventListener('click', function(event) {
-    const aboutInfoCopy = aboutInfo;
-    if (!$('include-ids').checked) {
-      aboutInfoCopy.details = aboutInfo.details.filter(function(el) {
-        return !el.is_sensitive;
-      });
-    }
-    let data = '';
-    data += new Date().toString() + '\n';
-    data += '======\n';
-    data += 'Status\n';
-    data += '======\n';
-    data += JSON.stringify(aboutInfoCopy, null, 2) + '\n';
-
-    $('status-text').value = data;
-    $('status-data').hidden = false;
-  });
-
-  const importStatusButton = $('import-status');
-  importStatusButton.addEventListener('click', function(event) {
-    $('status-data').hidden = false;
-    if ($('status-text').value.length === 0) {
-      $('status-text').value = 'Paste sync status dump here then click import.';
-      return;
-    }
-
-    // First remove any characters before the '{'.
-    let data = $('status-text').value;
-    const firstBrace = data.indexOf('{');
-    if (firstBrace < 0) {
-      $('status-text').value = 'Invalid sync status dump.';
-      return;
-    }
-    data = data.substr(firstBrace);
-
-    // Remove listeners to prevent sync events from overwriting imported data.
-    if (aboutInfoListener) {
-      removeWebUIListener(aboutInfoListener);
-      aboutInfoListener = null;
-    }
-
-    if (entityCountsUpdatedListener) {
-      removeWebUIListener(entityCountsUpdatedListener);
-      entityCountsUpdatedListener = null;
-    }
-
-    const aboutInfo = JSON.parse(data);
-    refreshAboutInfo(aboutInfo);
-  });
-}
-
-/**
- * Toggles the given traffic event entry div's "expanded" state.
- * @param {MouseEvent} e the click event that triggered the toggle.
- */
-function expandListener(e) {
-  if (e.target.classList.contains('proto')) {
-    // We ignore proto clicks to keep it copyable.
-    return;
-  }
-  let trafficEventDiv = e.target;
-  // Click might be on div's child.
-  if (trafficEventDiv.nodeName !== 'DIV') {
-    trafficEventDiv = trafficEventDiv.parentNode;
-  }
-  trafficEventDiv.classList.toggle('traffic-event-entry-expanded');
-}
-
-/**
- * Attaches a listener to the given traffic event entry div.
- * @param {HTMLElement} element the element to attach the listener to.
- */
-function addAboutExpandListener(element) {
-  element.addEventListener('click', expandListener, false);
-}
-
-function onLoad() {
-  initStatusDumpButton();
-  initProtocolEventLog();
-
-  aboutInfoListener = addWebUIListener('onAboutInfoUpdated', refreshAboutInfo);
-
-  entityCountsUpdatedListener =
-      addWebUIListener('onEntityCountsUpdated', onEntityCountsUpdatedEvent);
-
-  $('request-start').addEventListener('click', function(event) {
-    requestStart();
-  });
-  $('request-stop-keep-data').addEventListener('click', function(event) {
-    requestStopKeepData();
-  });
-  $('request-stop-clear-data').addEventListener('click', function(event) {
-    requestStopClearData();
-  });
-
-  // Request initial data for the page and listen to updates.
-  requestDataAndRegisterForUpdates();
-}
-
-// For JS eval.
-window.addAboutExpandListener = addAboutExpandListener;
-window.highlightIfChanged = highlightIfChanged;
-
-document.addEventListener('DOMContentLoaded', onLoad, false);
diff --git a/components/sync/driver/resources/about.ts b/components/sync/driver/resources/about.ts
new file mode 100644
index 0000000..9bb0e60
--- /dev/null
+++ b/components/sync/driver/resources/about.ts
@@ -0,0 +1,286 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/js/jstemplate_compiled.js';
+
+import {assert} from 'chrome://resources/js/assert_ts.js';
+import {addWebUIListener, removeWebUIListener, WebUIListener} from 'chrome://resources/js/cr.m.js';
+
+import {requestDataAndRegisterForUpdates, requestStart, requestStopClearData, requestStopKeepData, setIncludeSpecifics, triggerRefresh} from './chrome_sync.js';
+import {ProtocolEvent} from './traffic_log.js';
+
+// Contains the latest snapshot of sync about info.
+type TypeStatus = {
+  name: string,
+  num_entries: number,
+  num_live: number,
+};
+
+type Detail = {
+  is_sensitive: boolean,
+};
+
+export let aboutInfo: {details?: Detail[], type_status?: TypeStatus[]} = {};
+
+// For tests
+function getAboutInfoForTest() {
+  return aboutInfo;
+}
+
+let aboutInfoListener: WebUIListener|null = null;
+let entityCountsUpdatedListener: WebUIListener|null = null;
+
+function highlightIfChanged(node: HTMLElement, oldVal: number, newVal: number) {
+  const oldStr = oldVal.toString();
+  const newStr = newVal.toString();
+  if (oldStr !== '' && oldStr !== newStr) {
+    // Note the addListener function does not end up creating duplicate
+    // listeners.  There can be only one listener per event at a time.
+    // Reference: https://developer.mozilla.org/en/DOM/element.addEventListener
+    node.addEventListener('webkitAnimationEnd', function() {
+      node.removeAttribute('highlighted');
+    }, false);
+    node.setAttribute('highlighted', '');
+  }
+}
+
+function refreshAboutInfo(newAboutInfo: object) {
+  aboutInfo = newAboutInfo;
+  const aboutInfoDiv = document.querySelector<HTMLElement>('#about-info');
+  assert(aboutInfoDiv);
+  jstProcess(new JsEvalContext(aboutInfo), aboutInfoDiv);
+}
+
+type EntityCount = {
+  modelType: string,
+  entities: number,
+  nonTombstoneEntities: number,
+};
+
+function onEntityCountsUpdatedEvent(response: {entityCounts: EntityCount[]}) {
+  if (!aboutInfo.type_status) {
+    return;
+  }
+  for (const count of response.entityCounts) {
+    const typeStatusRow =
+        aboutInfo.type_status.find(row => row.name === count.modelType);
+    if (typeStatusRow) {
+      typeStatusRow.num_entries = count.entities;
+      typeStatusRow.num_live = count.nonTombstoneEntities;
+    }
+  }
+  const typeInfo = document.querySelector<HTMLElement>('#typeInfo');
+  assert(typeInfo);
+  jstProcess(new JsEvalContext({type_status: aboutInfo.type_status}), typeInfo);
+}
+
+/**
+ * Helper to determine if an element is scrolled to its bottom limit.
+ * @param elem element to check
+ * @return true if the element is scrolled to the bottom
+ */
+function isScrolledToBottom(elem: HTMLElement): boolean {
+  return elem.scrollHeight - elem.scrollTop === elem.clientHeight;
+}
+
+/**
+ * Helper to scroll an element to its bottom limit.
+ */
+function scrollToBottom(elem: HTMLElement) {
+  elem.scrollTop = elem.scrollHeight - elem.clientHeight;
+}
+
+/** Container for accumulated sync protocol events. */
+const protocolEvents: ProtocolEvent[] = [];
+
+/** We may receive re-delivered events.  Keep a record of ones we've seen. */
+const knownEventTimestamps: {[key: string]: boolean} = {};
+
+/**
+ * Callback for incoming protocol events.
+ * @param response The protocol event response.
+ */
+function onReceivedProtocolEvent(response: ProtocolEvent) {
+  // Return early if we've seen this event before.  Assumes that timestamps
+  // are sufficiently high resolution to uniquely identify an event.
+  if (knownEventTimestamps.hasOwnProperty(response.time)) {
+    return;
+  }
+
+  knownEventTimestamps[response.time] = true;
+  protocolEvents.push(response);
+
+  const trafficContainer =
+      document.querySelector<HTMLElement>('#traffic-event-container');
+  assert(trafficContainer);
+
+  // Scroll to the bottom if we were already at the bottom.  Otherwise, leave
+  // the scrollbar alone.
+  const shouldScrollDown = isScrolledToBottom(trafficContainer);
+
+  const context = new JsEvalContext({events: protocolEvents});
+  jstProcess(context, trafficContainer);
+
+  if (shouldScrollDown) {
+    scrollToBottom(trafficContainer);
+  }
+}
+
+/**
+ * Initializes state and callbacks for the protocol event log UI.
+ */
+function initProtocolEventLog() {
+  const includeSpecificsCheckbox =
+      document.querySelector<HTMLInputElement>('#capture-specifics');
+  assert(includeSpecificsCheckbox);
+  includeSpecificsCheckbox.addEventListener('change', () => {
+    setIncludeSpecifics(includeSpecificsCheckbox.checked);
+  });
+
+  addWebUIListener('onProtocolEvent', onReceivedProtocolEvent);
+
+  // Make the prototype jscontent element disappear.
+  const container =
+      document.querySelector<HTMLElement>('#traffic-event-container');
+  assert(container);
+  jstProcess({}, container);
+
+  const triggerRefreshButton =
+      document.querySelector<HTMLElement>('#trigger-refresh');
+  assert(triggerRefreshButton);
+  triggerRefreshButton.addEventListener('click', () => {
+    triggerRefresh();
+  });
+}
+
+/**
+ * Initializes listeners for status dump and import UI.
+ */
+function initStatusDumpButton() {
+  const statusData = document.querySelector<HTMLElement>('#status-data');
+  assert(statusData);
+  statusData.hidden = true;
+
+  const dumpStatusButton = document.querySelector<HTMLElement>('#dump-status');
+  assert(dumpStatusButton);
+  dumpStatusButton.addEventListener('click', () => {
+    const aboutInfoCopy = aboutInfo;
+    const includeIds = document.querySelector<HTMLInputElement>('#include-ids');
+    assert(includeIds);
+    if (!includeIds.checked) {
+      aboutInfoCopy.details = aboutInfo.details!.filter(function(el) {
+        return !el.is_sensitive;
+      });
+    }
+    let data = '';
+    data += new Date().toString() + '\n';
+    data += '======\n';
+    data += 'Status\n';
+    data += '======\n';
+    data += JSON.stringify(aboutInfoCopy, null, 2) + '\n';
+
+    const statusText =
+        document.querySelector<HTMLTextAreaElement>('#status-text');
+    assert(statusText);
+    statusText.value = data;
+    const statusData = document.querySelector<HTMLElement>('#status-data');
+    assert(statusData);
+    statusData.hidden = false;
+  });
+
+  const importStatusButton =
+      document.querySelector<HTMLElement>('#import-status');
+  assert(importStatusButton);
+  importStatusButton.addEventListener('click', () => {
+    const statusData = document.querySelector<HTMLElement>('#status-data');
+    assert(statusData);
+    statusData.hidden = false;
+    const statusText =
+        document.querySelector<HTMLTextAreaElement>('#status-text');
+    assert(statusText);
+    if (statusText.value.length === 0) {
+      statusText.value = 'Paste sync status dump here then click import.';
+      return;
+    }
+
+    // First remove any characters before the '{'.
+    let data = statusText.value;
+    const firstBrace = data.indexOf('{');
+    if (firstBrace < 0) {
+      statusText.value = 'Invalid sync status dump.';
+      return;
+    }
+    data = data.substr(firstBrace);
+
+    // Remove listeners to prevent sync events from overwriting imported data.
+    if (aboutInfoListener) {
+      removeWebUIListener(aboutInfoListener);
+      aboutInfoListener = null;
+    }
+
+    if (entityCountsUpdatedListener) {
+      removeWebUIListener(entityCountsUpdatedListener);
+      entityCountsUpdatedListener = null;
+    }
+
+    const aboutInfo = JSON.parse(data);
+    refreshAboutInfo(aboutInfo);
+  });
+}
+
+/**
+ * Toggles the given traffic event entry div's "expanded" state.
+ * @param e the click event that triggered the toggle.
+ */
+function expandListener(e: MouseEvent) {
+  if ((e.target as HTMLElement).classList.contains('proto')) {
+    // We ignore proto clicks to keep it copyable.
+    return;
+  }
+  let trafficEventDiv = e.target as HTMLElement;
+  // Click might be on div's child.
+  if (trafficEventDiv.nodeName !== 'DIV' && trafficEventDiv.parentNode) {
+    trafficEventDiv = trafficEventDiv.parentNode as HTMLElement;
+  }
+  trafficEventDiv.classList.toggle('traffic-event-entry-expanded');
+}
+
+/**
+ * Attaches a listener to the given traffic event entry div.
+ * @param element the element to attach the listener to.
+ */
+function addAboutExpandListener(element: HTMLElement) {
+  element.addEventListener('click', expandListener, false);
+}
+
+function onLoad() {
+  initStatusDumpButton();
+  initProtocolEventLog();
+
+  aboutInfoListener = addWebUIListener('onAboutInfoUpdated', refreshAboutInfo);
+
+  entityCountsUpdatedListener =
+      addWebUIListener('onEntityCountsUpdated', onEntityCountsUpdatedEvent);
+
+  const requestStartEl = document.querySelector<HTMLElement>('#request-start');
+  assert(requestStartEl);
+  requestStartEl.addEventListener('click', requestStart);
+  const requestStopKeepDataEl =
+      document.querySelector<HTMLElement>('#request-stop-keep-data');
+  assert(requestStopKeepDataEl);
+  requestStopKeepDataEl.addEventListener('click', requestStopKeepData);
+  const requestStopClearDataEl =
+      document.querySelector<HTMLElement>('#request-stop-clear-data');
+  assert(requestStopClearDataEl);
+  requestStopClearDataEl.addEventListener('click', requestStopClearData);
+
+  // Request initial data for the page and listen to updates.
+  requestDataAndRegisterForUpdates();
+}
+
+// For JS eval and tests.
+Object.assign(
+    window, {addAboutExpandListener, getAboutInfoForTest, highlightIfChanged});
+
+document.addEventListener('DOMContentLoaded', onLoad, false);
diff --git a/components/sync/driver/resources/chrome_sync.ts b/components/sync/driver/resources/chrome_sync.ts
index 1bd188a..a57d68b 100644
--- a/components/sync/driver/resources/chrome_sync.ts
+++ b/components/sync/driver/resources/chrome_sync.ts
@@ -99,17 +99,23 @@
 }
 
 export type SyncNode = {
+  BASE_VERSION: string,
+  BASE_VERSION_STRING: string,
   ID: string,
   IS_DIR: boolean,
   METAHANDLE: number,
   NON_UNIQUE_NAME: string,
   PARENT_ID: string,
   UNIQUE_SERVER_TAG: string,
+  SERVER_VERSION: string,
+  SERVER_VERSION_TIME: string,
+  SERVER_SPECIFICS: string,
+  SPECIFICS: string,
   modelType: string,
   positionIndex?: number,
 };
 
-export type SyncNodeMap = Array<{nodes: SyncNode[]}>;
+export type SyncNodeMap = Array<{type: string, nodes: SyncNode[]}>;
 
 let nodesForTest: SyncNodeMap|null = null;
 
diff --git a/components/sync/driver/resources/data.js b/components/sync/driver/resources/data.ts
similarity index 64%
rename from components/sync/driver/resources/data.js
rename to components/sync/driver/resources/data.ts
index 3b5a39b..2038df4f 100644
--- a/components/sync/driver/resources/data.js
+++ b/components/sync/driver/resources/data.ts
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {addWebUIListener, removeWebUIListener} from 'chrome://resources/js/cr.m.js';
-import {$} from 'chrome://resources/js/util.m.js';
+import {assert} from 'chrome://resources/js/assert_ts.js';
+import {addWebUIListener, removeWebUIListener, WebUIListener} from 'chrome://resources/js/cr.m.js';
 
 import {aboutInfo} from './about.js';
-import {getAllNodes, requestIncludeSpecificsInitialState, requestListOfTypes} from './chrome_sync.js';
+import {getAllNodes, requestIncludeSpecificsInitialState, requestListOfTypes, SyncNode, SyncNodeMap} from './chrome_sync.js';
 import {log} from './sync_log.js';
 
-const dumpToTextButton = $('dump-to-text');
-const dataDump = $('data-dump');
-dumpToTextButton.addEventListener('click', function(event) {
+const dumpToTextButton = document.querySelector<HTMLElement>('#dump-to-text');
+assert(dumpToTextButton);
+const dataDump = document.querySelector<HTMLElement>('#data-dump');
+assert(dataDump);
+dumpToTextButton.addEventListener('click', function() {
   // TODO(akalin): Add info like Chrome version, OS, date dumped, etc.
 
   let data = '';
@@ -48,7 +50,7 @@
   'SPECIFICS',
 ];
 
-function versionToDateString(version) {
+function versionToDateString(version: string) {
   // TODO(mmontgomery): ugly? Hacky? Is there a better way?
   const epochLength = Date.now().toString().length;
   const epochTime = parseInt(version.slice(0, epochLength), 10);
@@ -57,10 +59,13 @@
 }
 
 /**
- * @param {!Object} node A JavaScript represenation of a sync entity.
- * @return {!Array<string>} A string representation of the sync entity.
+ * @param node A JavaScript represenation of a sync entity.
+ * @return A string representation of the sync entity.
  */
-function serializeNode(node) {
+function serializeNode(node: SyncNode): string[] {
+  const includeSpecifics =
+      document.querySelector<HTMLInputElement>('#include-specifics');
+  assert(includeSpecifics);
   return allFields.map(function(field) {
     let fieldVal;
     if (field === 'SERVER_VERSION_TIME') {
@@ -76,25 +81,25 @@
       }
     } else if (
         (field === 'SERVER_SPECIFICS' || field === 'SPECIFICS') &&
-        (!$('include-specifics').checked)) {
+        (!includeSpecifics.checked)) {
       fieldVal = 'REDACTED';
     } else if (
         (field === 'SERVER_SPECIFICS' || field === 'SPECIFICS') &&
-        $('include-specifics').checked) {
+        includeSpecifics.checked) {
       fieldVal = JSON.stringify(node[field]);
     } else {
-      fieldVal = node[field];
+      fieldVal = (node as unknown as {[key: string]: string})[field];
     }
-    return fieldVal;
+    return fieldVal || '';
   });
 }
 
 /**
- * @param {string} type The name of a sync model type.
- * @return {boolean} True if the type's checkbox is selected.
+ * @param type The name of a sync model type.
+ * @return True if the type's checkbox is selected.
  */
-function isSelectedDatatype(type) {
-  const typeCheckbox = $(type);
+function isSelectedDatatype(type: string): boolean {
+  const typeCheckbox = document.querySelector<HTMLInputElement>(`#${type}`);
   // Some types, such as 'Top level folder', appear in the list of nodes
   // but not in the list of selectable items.
   if (typeCheckbox == null) {
@@ -103,7 +108,7 @@
   return typeCheckbox.checked;
 }
 
-function makeBlobUrl(data) {
+function makeBlobUrl(data: string): string {
   const textBlob = new Blob([data], {type: 'octet/stream'});
   const blobUrl = window.URL.createObjectURL(textBlob);
   return blobUrl;
@@ -130,12 +135,11 @@
 /**
  * Builds a summary of current state and exports it as a downloaded file.
  *
- * @param {!Array<{type: string, nodes: !Array<!Object>}>} nodesMap
- *     Summary of local state by model type.
+ * @param nodesMap Summary of local state by model type.
  */
-function triggerDataDownload(nodesMap) {
+function triggerDataDownload(nodesMap: SyncNodeMap) {
   // Prepend a header with ISO date and useragent.
-  let output = [makeDateUserAgentHeader()];
+  const output = [makeDateUserAgentHeader()];
   output.push('=====');
 
   const aboutInfoString = JSON.stringify(aboutInfo, null, 2);
@@ -152,24 +156,28 @@
     output.push(typeNodes.nodes.map(serializeNode).join('\n'));
   });
 
-  output = output.join('\n');
+  const outputString = output.join('\n');
 
-  const anchor = $('dump-to-file-anchor');
-  anchor.href = makeBlobUrl(output);
+  const anchor =
+      document.querySelector<HTMLAnchorElement>('#dump-to-file-anchor');
+  assert(anchor);
+  anchor.href = makeBlobUrl(outputString);
   anchor.download = makeDownloadName();
   anchor.click();
 }
 
-function createTypesCheckboxes(types) {
-  const containerElt = $('node-type-checkboxes');
+function createTypesCheckboxes(types: string[]) {
+  const containerElt =
+      document.querySelector<HTMLElement>('#node-type-checkboxes');
+  assert(containerElt);
 
-  types.map(function(type) {
+  types.map(function(type: string) {
     const div = document.createElement('div');
 
     const checkbox = document.createElement('input');
     checkbox.id = type;
     checkbox.type = 'checkbox';
-    checkbox.checked = 'yes';
+    checkbox.checked = true;
     div.appendChild(checkbox);
 
     const label = document.createElement('label');
@@ -182,17 +190,22 @@
   });
 }
 
-let listOfTypesListener = null;
+let listOfTypesListener: WebUIListener|null = null;
 
-function onReceivedListOfTypes(response) {
+function onReceivedListOfTypes(response: {types: string[]}) {
   const types = response.types;
   types.sort();
   createTypesCheckboxes(types);
+  assert(listOfTypesListener);
   removeWebUIListener(listOfTypesListener);
 }
 
-function onReceivedIncludeSpecificsInitialState(response) {
-  $('capture-specifics').checked = response.includeSpecifics;
+function onReceivedIncludeSpecificsInitialState(
+    response: {includeSpecifics: boolean}) {
+  const captureSpecifics =
+      document.querySelector<HTMLInputElement>('#capture-specifics');
+  assert(captureSpecifics);
+  captureSpecifics.checked = response.includeSpecifics;
 }
 
 document.addEventListener('DOMContentLoaded', function() {
@@ -206,7 +219,8 @@
   requestIncludeSpecificsInitialState();
 });
 
-const dumpToFileLink = $('dump-to-file');
-dumpToFileLink.addEventListener('click', function(event) {
+const dumpToFileLink = document.querySelector<HTMLElement>('#dump-to-file');
+assert(dumpToFileLink);
+dumpToFileLink.addEventListener('click', function() {
   getAllNodes(triggerDataDownload);
 });
diff --git a/components/sync/driver/resources/traffic_log.ts b/components/sync/driver/resources/traffic_log.ts
index 362b932..00a4fa0 100644
--- a/components/sync/driver/resources/traffic_log.ts
+++ b/components/sync/driver/resources/traffic_log.ts
@@ -9,7 +9,7 @@
 
 let instance: TrafficLogTag|null = null;
 
-type ProtocolEvent = {
+export type ProtocolEvent = {
   time: string,
 };
 
diff --git a/components/test/data/autofill/automated_integration/__init__.py b/components/test/data/autofill/automated_integration/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/components/test/data/autofill/automated_integration/__init__.py
+++ /dev/null
diff --git a/components/test/data/autofill/automated_integration/autofill_task/__init__.py b/components/test/data/autofill/automated_integration/autofill_task/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/__init__.py
+++ /dev/null
diff --git a/components/test/data/autofill/automated_integration/autofill_task/actions.py b/components/test/data/autofill/automated_integration/autofill_task/actions.py
deleted file mode 100644
index beff03fe..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/actions.py
+++ /dev/null
@@ -1,405 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import abc
-import sys
-import traceback
-import time
-
-from selenium.common.exceptions import TimeoutException
-from selenium.webdriver.common.by import By
-from selenium.webdriver.common.keys import Keys
-from selenium.webdriver.common.action_chains import ActionChains
-from selenium.webdriver.support.ui import WebDriverWait, Select as SelectElement
-from selenium.webdriver.support import expected_conditions as EC
-
-
-class _ElementSelector(object):
-  """Base class for all element selectors."""
-  key_type = None
-
-  def __init__(self, key, index=0):
-    """Constructor.
-
-    Args:
-      key: A string which acts as the selector for the element.
-      # index: A selector for which instance of the key should be returned.
-
-    Returns:
-      A webdriver element if found, or None.
-    """
-
-    self._key = key
-    # self._index = index
-
-  def __str__(self):
-    return '\'%s\' by %s' % (self._key, self.key_type)
-
-  def tuple(self):
-    return (self.key_type, self._key)
-
-
-class ByID(_ElementSelector):
-  """Select an element by its id."""
-  key_type = By.ID
-
-
-class ByClassName(_ElementSelector):
-  """Select an element by its class name."""
-  key_type = By.CLASS_NAME
-
-
-class ByCssSelector(_ElementSelector):
-  """Select an element by its class name."""
-  key_type = By.CSS_SELECTOR
-
-
-class ByXPath(_ElementSelector):
-  """Select an element by its xpath."""
-  key_type = By.XPATH
-
-
-class _Action(object):
-  """Base class for all actions."""
-
-  __metaclass__ = abc.ABCMeta
-
-  def Apply(self, driver, test, debug=False):
-    self._debug = debug
-
-    self._dprint('Trying to %s ' % self)
-
-    if self._ignorable:
-      assert_function = test.expect_expression
-    else:
-      assert_function = test.assert_expression
-
-    try:
-      response = self._Apply(driver, test)
-      if response:
-        self._dprint('  Success')
-      else:
-        self._dprint('  Failure')
-      assert_function(response, 'Failed to %s' % self)
-    except TimeoutException:
-      self._dprint('  Failure: TimeoutException')
-      stack = traceback.extract_tb(sys.exc_info()[2])
-      assert_function(False, 'Failed to %s\nTimeoutException' % self, stack)
-
-  def _dprint(self, msg):
-    if self._debug:
-      print(msg)
-
-  @abc.abstractmethod
-  def _Apply(self, driver, test):
-    """The type-specific action execution implementation.
-
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method
-    """
-    raise NotImplementedError()
-
-
-class SetContext(_Action):
-  """Sets an element (iframe) as the current driver context.
-
-  If element_selector is None then it will be reset to root.
-  """
-
-  def __init__(self, element_selector, ignorable=False):
-    self._element_selector = element_selector
-    self._ignorable = ignorable
-
-  def __str__(self):
-    if self._element_selector is None:
-      return 'Set context to default'
-    else:
-      return 'Set context to %s' % self._element_selector
-
-  def _Apply(self, driver, test):
-    if self._element_selector is None:
-      driver.switch_to_default_content()
-    else:
-      wt = WebDriverWait(driver, 30) # seconds
-      locator = self._element_selector.tuple()
-      element = wt.until(EC.frame_to_be_available_and_switch_to_it(locator))
-
-    return True
-
-
-class Open(_Action):
-  """Open a URL."""
-
-  def __init__(self, url):
-    self._url = url
-    self._ignorable = False
-
-  def __str__(self):
-    return 'Open %s' % self._url
-
-  def _Apply(self, driver, unused_test):
-    try:
-      driver.get(self._url)
-    except TimeoutException:
-      self._dprint(('  TimeoutException raised when loading %s\n'
-                    '  Proceeding regardless') % (self._url))
-    # Return true regardless as a slow-loading page probably means that there's
-    # an non-critical script
-    return True
-
-
-class Type(_Action):
-  """Type some text into a field."""
-
-  def __init__(self, element_selector, text, ignorable=False):
-    self._element_selector = element_selector
-    self._text = text
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Type \'%s\' into %s' % (self._text, self._element_selector)
-
-  def _Apply(self, driver, test):
-    wt = WebDriverWait(driver, 30) # seconds
-    locator = self._element_selector.tuple()
-    element = wt.until(EC.presence_of_element_located(locator))
-    ActionChains(driver).move_to_element(element).perform()
-    time.sleep(0.1)
-    element = wt.until(EC.element_to_be_clickable(locator))
-    ActionChains(driver).click(element).perform()
-    element.send_keys(self._text)
-    return True
-
-
-class Select(_Action):
-  """Select a value from a select input field."""
-
-  def __init__(self, element_selector, value, ignorable=False, by_label=False):
-    self._element_selector = element_selector
-    self._value = value
-    self._ignorable = ignorable
-    self._by_label = by_label
-
-  def __str__(self):
-    return 'Select \'%s\' from %s%s' % (self._value,
-                                        self._element_selector,
-                                        (' by label' if self._by_label else ''))
-
-  def _Apply(self, driver, test):
-    wt = WebDriverWait(driver, 30)  # seconds
-    locator = self._element_selector.tuple()
-    element = wt.until(EC.presence_of_element_located(locator))
-    ActionChains(driver).move_to_element(element).perform()
-    element = wt.until(EC.element_to_be_clickable(locator))
-    select = SelectElement(element)
-    if self._by_label:
-      select.select_by_visible_text(self._value)
-    else:
-      select.select_by_value(self._value)
-    return True
-
-
-class Wait(_Action):
-  """Wait for a specified number of seconds."""
-
-  def __init__(self, seconds, ignorable=False):
-    self._seconds = seconds
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Wait %d seconds' % self._seconds
-
-  def _Apply(self, driver, test):
-    time.sleep(self._seconds)
-    return True
-
-
-class Screenshot(_Action):
-  """Print a base 64 encoded screenshot to stdout."""
-
-  def __init__(self, filename, ignorable=False):
-    self._filename = filename
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Screenshot'
-
-  def _Apply(self, driver, test):
-    sys.stdout.write(driver.get_screenshot_as_base64())
-    driver.get_screenshot_as_file(self._filename)
-    return True
-
-
-class Click(_Action):
-  """Click on an element."""
-
-  def __init__(self, element_selector, ignorable=False):
-    self._element_selector = element_selector
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Click %s' % self._element_selector
-
-  def _Apply(self, driver, test):
-    wt = WebDriverWait(driver, 10)  # seconds
-    locator = self._element_selector.tuple()
-    element = wt.until(EC.presence_of_element_located(locator))
-    ActionChains(driver).move_to_element(element).perform()
-    wt = WebDriverWait(driver, 10)  # seconds
-    element = wt.until(EC.element_to_be_clickable(locator))
-    element.click()
-    return True
-
-
-class TriggerAutofill(_Action):
-  """Trigger autofill using a form field."""
-
-  def __init__(self, element_selector, expected_type, trigger_character=None,
-               ignorable=False):
-    self._element_selector = element_selector
-    self._expected_type = expected_type
-    self._trigger_character = trigger_character
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Trigger Autofill %s' % self._element_selector
-
-  def _Apply(self, driver, test):
-    expected_value = test.profile_data(self._expected_type)
-    if expected_value != '':
-      if self._trigger_character is None:
-        trigger_character = expected_value[0]
-      else:
-        trigger_character = self._trigger_character
-    else:
-      test.expect_expression(
-          overall_type,
-          'Failure: Cannot trigger autofill, field_type \'%s\' '
-          'does not have an expected value' % self._expected_type)
-      return
-
-    locator = self._element_selector.tuple()
-    wt = WebDriverWait(driver, 15)  # seconds
-    element = wt.until(EC.presence_of_element_located(locator))
-    ActionChains(driver).move_to_element(element).perform()
-    wt = WebDriverWait(driver, 10)  # seconds
-    element = wt.until(EC.element_to_be_clickable(locator))
-    ActionChains(driver).click(element).perform()
-    time.sleep(1)
-    actions = ActionChains(driver)
-    actions.send_keys(trigger_character)
-    actions.perform()
-    time.sleep(0.5)
-    actions = ActionChains(driver)
-    actions.key_down(Keys.ARROW_DOWN)
-    actions.key_down(Keys.ENTER)
-    actions.perform()
-    time.sleep(1)
-
-    return True
-
-
-class ValidateFields(_Action):
-  """Assert that each field has its expected type and has been correctly filled.
-  """
-
-  def __init__(self, field_data_tuples, ignorable=False):
-    self._field_data_tuples = field_data_tuples
-    self._ignorable = ignorable
-
-  def __str__(self):
-    return 'Validate Fields:'
-
-  def _VerifyField(self, driver, test, selector, expected_type,
-                   custom_expected_value=None):
-    try:
-      wt = WebDriverWait(driver, 30)  # seconds
-      element = wt.until(EC.presence_of_element_located(selector.tuple()))
-
-      overall_type = element.get_attribute('autofill-prediction')
-
-      if overall_type is None:
-        test.expect_expression(
-            overall_type,
-            'Failure: Cannot verify field type, autofill-prediction attribute '
-            'not set for \'%s\'' % selector)
-        return
-
-      response = True
-
-      self._dprint('    Checking detected field type')
-      field_type_response = overall_type == expected_type
-      test.expect_expression(field_type_response,
-                             'Field type %s does not match %s' %
-                             (overall_type, expected_type))
-      if field_type_response:
-        self._dprint('      Success')
-      else:
-        response = False
-        self._dprint('      Failure: actual overall_type is %s' % overall_type)
-
-
-      self._dprint('    Checking autofilled data')
-      field_value = element.get_attribute('value')
-
-      if custom_expected_value is None:
-        expected_value = test.profile_data(expected_type)
-        if expected_value == '':
-          test.expect_expression(
-              overall_type,
-              'Failure: Cannot verify field value, expected_type \'%s\' does '
-              'not have an expected value' % expected_type)
-          return
-      else:
-        expected_value = custom_expected_value
-
-      field_value_response = field_value == expected_value
-      test.expect_expression(field_value_response,
-                             'Field value \'%s\' does not match \'%s\'' %
-                             (field_value, expected_value))
-      if field_value_response:
-        self._dprint('      Success')
-      else:
-        response = False
-        self._dprint('      Failure: Actual field value is \'%s\'' %
-                     field_value)
-
-      # The same field type.
-      return response
-    except TimeoutException:
-      test.expect_expression(False,
-                             'Failure: Cannot verify field type, input element '
-                             '\'%s\' unavailable' % selector)
-      return False
-
-  def _Apply(self, driver, test):
-    response = True
-
-    for field_data_tuple in self._field_data_tuples:
-      field_data_size = len(field_data_tuple)
-      if field_data_size == 2:
-        selector, expected_type = field_data_tuple
-        custom_expected_value = None
-      elif field_data_size == 3:
-        selector, expected_type, custom_expected_value = field_data_tuple
-      else:
-        raise ValueError('Field data tuples must have either 2 or 3 elements.')
-
-      self._dprint('  %s: %s' % (expected_type, selector))
-
-      response = self._VerifyField(driver, test, selector, expected_type,
-                                   custom_expected_value)
-
-      if response:
-        self._dprint('    Success')
-      else:
-        response = False
-        self._dprint('    Failure')
-
-    if not self._ignorable:
-      test.assert_expectations();
-
-    return response
diff --git a/components/test/data/autofill/automated_integration/autofill_task/autofill_task.py b/components/test/data/autofill/automated_integration/autofill_task/autofill_task.py
deleted file mode 100644
index 24d326b..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/autofill_task.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Autofill task automation library.
-"""
-
-import abc
-
-# Local imports
-from .soft_task import SoftTask
-
-
-class AutofillTask(SoftTask):
-  """Extendable autofill task that provides soft/hard assertion functionality.
-
-  The task consists of a script (list of Actions) that are to be executed when
-  run.
-
-  Attributes:
-    profile_data: Dict of profile data that acts as the master source for
-      validating autofill behaviour.
-    debug: Whether debug output should be printed (False if not specified).
-  """
-
-  script = []
-
-  def __init__(self, profile_data, debug=False):
-    super(AutofillTask, self).__init__()
-    self._profile_data = profile_data
-    self._debug = debug
-
-  def __str__(self):
-    return self.__class__.__name__
-
-  @abc.abstractmethod
-  def _create_script(self):
-    """Creates a script (list of Actions) to execute.
-
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method.
-    """
-    raise NotImplementedError()
-
-  def set_up(self):
-    """Sets up the task by creating the action script.
-
-    Raises:
-      NotImplementedError: Subclass did not implement _create_script()
-    """
-    self._create_script()
-
-  def tear_down(self):
-    """Tears down the task running environment.
-
-    Any persistent changes made by set_up() must be reversed here.
-    """
-    pass
-
-  def run(self, driver):
-    """Sets up, attempts to execute the task, and always tears down.
-
-    Args:
-      driver: ChromeDriver instance to use for action execution.
-
-    Raises:
-      Exception: Task execution failed.
-    """
-    self._driver = driver
-    super(AutofillTask, self).run()
-
-  def _run_task(self):
-    """Executes the script defined by the subclass.
-
-    Raises:
-      Exception: Script execution failed.
-    """
-    for step in self.script:
-      step.Apply(self._driver, self, self._debug)
-
-    self.assert_expectations()
-
-  def profile_data(self, field):
-    if field in self._profile_data:
-      return self._profile_data[field]
-    else:
-      return ''
diff --git a/components/test/data/autofill/automated_integration/autofill_task/exceptions.py b/components/test/data/autofill/automated_integration/autofill_task/exceptions.py
deleted file mode 100644
index 9fa8bbb9..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/exceptions.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-class ExpectationFailure(Exception):
-  """Represents an unsatisfied expectation.
-  """
-  def __init__(self, *args,**kwargs):
-    super(ExpectationFailure, self).__init__(*args, **kwargs)
diff --git a/components/test/data/autofill/automated_integration/autofill_task/generator.py b/components/test/data/autofill/automated_integration/autofill_task/generator.py
deleted file mode 100644
index 73281f4..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/generator.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from random import choice
-from string import ascii_lowercase
-
-
-class Generator(object):
-  """A string generator utility.
-  """
-  def __init__(self):
-    super(Generator, self).__init__()
-
-  @staticmethod
-  def _lower_case_string(length=8):
-    return ''.join(choice(ascii_lowercase) for i in range(length))
-
-  @staticmethod
-  def email():
-    """Generates a fake email address.
-
-    Format: 8 character string at an 8 character .com domain name
-
-    Returns: The generated email address string.
-    """
-    return '%s@%s.com' % (Generator._lower_case_string(),
-                          Generator._lower_case_string())
-
-  @staticmethod
-  def password():
-    """Generates a fake password.
-
-    Format: 8 character lowercase string plus 'A!234&'
-      The postpended string exists to assist in satisfying common "secure
-      password" requirements
-
-    Returns: The generated password string.
-    """
-    return 'A!234&%s' % Generator._lower_case_string()
diff --git a/components/test/data/autofill/automated_integration/autofill_task/soft_task.py b/components/test/data/autofill/automated_integration/autofill_task/soft_task.py
deleted file mode 100644
index 304b20b..0000000
--- a/components/test/data/autofill/automated_integration/autofill_task/soft_task.py
+++ /dev/null
@@ -1,182 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import abc
-import inspect
-import os.path
-import sys
-
-# Local Imports
-from .exceptions import ExpectationFailure
-
-
-class SoftTask(object):
-  """An extendable base task that provides soft/hard assertion functionality.
-  """
-  __metaclass__ = abc.ABCMeta
-
-  def __init__(self):
-    self._failed_expectations = []
-
-  @abc.abstractmethod
-  def set_up(self):
-    """Sets up the task running environment.
-
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def tear_down(self):
-    """Tears down the task running environment.
-
-    Any persistent changes made by set_up() must be reversed here.
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method
-    """
-    raise NotImplementedError()
-
-  @abc.abstractmethod
-  def _run_task(self):
-    """Executes the task.
-
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method
-    """
-    raise NotImplementedError()
-
-  def run(self):
-    """Sets up, attempts to execute the task, and always tears down.
-
-    Raises:
-      ExpectationFailure: Task execution failed. Contains a
-      NotImplementedError: Subclass did not implement the abstract methods
-    """
-    self.set_up()
-    try:
-      self._run_task()
-    finally:
-      # Attempt to tear down despite test failure
-      self.tear_down()
-
-  def expect_expression(self, expr, msg=None, stack=None):
-    """Verifies an expression, logging a failure, but not abort the test.
-
-    In order to ensure that none of the expected expressions have failed, one
-    must call assert_expectations before the end of the test (which will fail
-    it if any expectations were not met).
-    """
-    if not expr:
-      self._log_failure(msg, stack=stack)
-
-  def assert_expression(self, expr, msg=None, stack=None):
-    """Perform a hard assertion but include failures from soft expressions too.
-
-    Raises:
-      ExpectationFailure: This or previous assertions did not pass. Contains a
-        failure report.
-    """
-    if not expr:
-      self._log_failure(msg, stack=stack)
-      if self._failed_expectations:
-        raise ExpectationFailure(self._report_failures())
-
-  def assert_expectations(self):
-    """Raise an assert if there were any failed expectations.
-
-    Raises:
-      ExpectationFailure: An expectation was not met. Contains a failure report.
-    """
-    if self._failed_expectations:
-      raise ExpectationFailure(self._report_failures())
-
-  def _log_failure(self, msg=None, frames=7, skip_frames=0, stack=None):
-    """Generates a failure report from the current traceback.
-
-    The generated failure report is added to an internal list. The reports
-    are used by _report_failures
-
-    Note: Since this is always called internally a minimum of two frames are
-    dropped unless you provide a specific stack trace.
-
-    Args:
-      msg: Description of the failure.
-      frames: The number of frames to include from the call to this function.
-      skip_frames: The number of frames to skip. Useful if you have helper
-        functions that you don't desire to be part of the trace.
-      stack: A custom traceback to use instead of one from this function. No
-        frames will be skipped by default.
-    """
-    if msg:
-      failure_message = msg + '\n'
-    else:
-      failure_message = '\n'
-
-    if stack is None:
-      stack = inspect.stack()[skip_frames + 2:]
-    else:
-      stack = stack[skip_frames:]
-
-    frames_to_use = min(frames, len(stack))
-    stack = stack[:frames_to_use]
-
-    for frame in stack:
-      # First two frames are from logging
-      if len(frame) == 4:
-        # From the traceback module
-        (filename, line, function_name, context) = frame
-        context = '    %s\n' % context
-      else:
-        # Stack trace from the inspect module
-        (filename, line, function_name, context_list) = frame[1:5]
-        context = context_list[0]
-      filename = os.path.basename(filename)
-
-      failure_message += '  File "%s", line %s, in %s()\n%s' % (filename, line,
-                                                                function_name,
-                                                                context)
-
-    self._failed_expectations.append(failure_message)
-
-  def _report_failures(self, frames=1, skip_frames=0):
-    """Generates a failure report for all failed expectations.
-
-    Used in exception descriptions.
-
-    Note: Since this is always called internally a minimum of two frames are
-    dropped.
-
-    Args:
-      frames: The number of frames to include from the call to this function.
-      skip_frames: The number of frames to skip. Useful if you have helper
-        functions that you don't desire to be part of the trace.
-
-    Returns:
-      A string representation of all failed expectations.
-    """
-    if self._failed_expectations:
-      # First two frames are from logging
-      (filename, line, function_name) = inspect.stack()[skip_frames + 2][1:4]
-      filename = os.path.basename(filename)
-
-      report = [
-          'Failed Expectations: %s\n' % len(self._failed_expectations),
-          'assert_expectations() called from',
-          '"%s" line %s, in %s()\n' % (filename, line, function_name)
-      ]
-
-      for i, failure in enumerate(self._failed_expectations, start=1):
-        report.append('Expectation %d: %s' % (i, failure))
-
-      self._failed_expectations = []
-      return '\n'.join(report)
-    else:
-      return ''
diff --git a/components/test/data/autofill/automated_integration/autofill_test/__init__.py b/components/test/data/autofill/automated_integration/autofill_test/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/components/test/data/autofill/automated_integration/autofill_test/__init__.py
+++ /dev/null
diff --git a/components/test/data/autofill/automated_integration/autofill_test/case.py b/components/test/data/autofill/automated_integration/autofill_test/case.py
deleted file mode 100644
index 7c77b00e..0000000
--- a/components/test/data/autofill/automated_integration/autofill_test/case.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import sys
-import unittest
-
-from selenium.common.exceptions import TimeoutException
-
-# Local Imports
-from autofill_task.exceptions import ExpectationFailure
-from .flow import AutofillTestFlow
-
-class AutofillTestCase(unittest.TestCase):
-  """Wraps a single autofill test flow for use with the unittest library.
-
-    task_class: AutofillTask to use for the test.
-    profile: Dict of profile data that acts as the master source for
-      validating autofill behaviour.
-    debug: Whether debug output should be printed (False if not specified).
-  """
-  def __init__(self, task_class, user_data_dir, profile, chrome_binary=None,
-               debug=False):
-    super(AutofillTestCase, self).__init__('run')
-    self._flow = AutofillTestFlow(task_class, profile, debug=debug)
-    self._user_data_dir = user_data_dir
-    self._chrome_binary = chrome_binary
-    self._debug = debug
-
-  def __str__(self):
-    return str(self._flow)
-
-  def run(self, result):
-    result.startTest(self)
-
-    try:
-      self._flow.run(self._user_data_dir, chrome_binary=self._chrome_binary)
-    except KeyboardInterrupt:
-      raise
-    except (TimeoutException, ExpectationFailure):
-      result.addFailure(self, sys.exc_info())
-    except:
-      result.addError(self, sys.exc_info())
-    else:
-      result.addSuccess(self)
-    finally:
-      result.stopTest(self)
diff --git a/components/test/data/autofill/automated_integration/autofill_test/flow.py b/components/test/data/autofill/automated_integration/autofill_test/flow.py
deleted file mode 100644
index 4cb56bde..0000000
--- a/components/test/data/autofill/automated_integration/autofill_test/flow.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Chrome Autofill Test Flow
-
-Execute a set of autofill tasks in a fresh ChromeDriver instance that has been
-pre-loaded with some default profile.
-
-Requires:
-  - Selenium python bindings
-    http://selenium-python.readthedocs.org/
-
-  - ChromeDriver
-    https://sites.google.com/a/chromium.org/chromedriver/downloads
-    The ChromeDriver executable must be available on the search PATH.
-
-  - Chrome (>= 53)
-"""
-
-# Local Imports
-from task_flow import TaskFlow
-
-
-class AutofillTestFlow(TaskFlow):
-  """Represents an executable set of Autofill Tasks.
-
-  Note: currently the test flows consist of a single AutofillTask
-
-  Used for automated autofill integration testing.
-
-  Attributes:
-    task_class: AutofillTask to use for the test.
-    profile: Dict of profile data that acts as the master source for
-      validating autofill behaviour.
-    debug: Whether debug output should be printed (False if not specified).
-  """
-  def __init__(self, task_class, profile, debug=False):
-    self._task_class = task_class
-    super(AutofillTestFlow, self).__init__(profile, debug)
-
-  def _generate_task_sequence(self):
-    """Generates a set of executable tasks that will be run in ChromeDriver.
-
-    Returns:
-      A list of AutofillTask instances that are to be run in ChromeDriver.
-
-      These tasks are to be run in order.
-    """
-
-    task = self._task_class(self._profile, self._debug)
-    return [task]
-
-  def __str__(self):
-    if self._tasks:
-      return 'Autofill Test Flow using \'%s\'' % self._tasks[0]
-    else:
-      return 'Empty Autofill Test Flow'
diff --git a/components/test/data/autofill/automated_integration/autofill_test/runner.py b/components/test/data/autofill/automated_integration/autofill_test/runner.py
deleted file mode 100644
index d8a8705..0000000
--- a/components/test/data/autofill/automated_integration/autofill_test/runner.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import unittest
-
-
-class AutofillTestResult(unittest.TextTestResult):
-  """A test result class that can print formatted text results to a stream.
-
-  Used by AutofillTestRunner.
-  """
-
-  def startTest(self, test):
-    """Called when a test is started.
-    """
-    super(unittest.TextTestResult, self).startTest(test)
-    if self.showAll:
-      self.stream.write('Running ')
-      self.stream.write(self.getDescription(test))
-      self.stream.write('\n')
-      self.stream.flush()
-
-  def addFailure(self, test, err):
-    """Logs a test failure as part of the specified test.
-
-    Overloaded to not include the stack trace.
-
-    Args:
-      err: A tuple of values as returned by sys.exc_info().
-    """
-    err = (None, err[1], None)
-    # self.failures.append((test, str(exception)))
-    # self._mirrorOutput = True
-    super(AutofillTestResult, self).addFailure(test, err)
-
-
-class AutofillTestRunner(unittest.TextTestRunner):
-  """An autofill test runner class that displays results in textual form.
-
-  It prints out the names of tests as they are run, errors as they
-  occur, and a summary of the results at the end of the test run.
-  """
-  resultclass = AutofillTestResult
diff --git a/components/test/data/autofill/automated_integration/autofill_test/suite.py b/components/test/data/autofill/automated_integration/autofill_test/suite.py
deleted file mode 100644
index 4aad1db3..0000000
--- a/components/test/data/autofill/automated_integration/autofill_test/suite.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Chrome Autofill Test Flow
-
-Execute a set of autofill tasks in a fresh ChromeDriver instance that has been
-pre-loaded with some default profile.
-
-Requires:
-  - Selenium python bindings
-    http://selenium-python.readthedocs.org/
-
-  - ChromeDriver
-    https://sites.google.com/a/chromium.org/chromedriver/downloads
-    The ChromeDriver executable must be available on the search PATH.
-
-  - Chrome
-"""
-
-import importlib
-import unittest
-
-# Local Imports
-from autofill_task.autofill_task import AutofillTask
-from testdata import profile_data
-from .case import AutofillTestCase
-
-
-class AutofillTestSuite(unittest.TestSuite):
-  """Represents an aggregation of individual Autofill test cases.
-
-  Attributes:
-    user_data_dir: Path string for the writable directory in which profiles
-      should be stored.
-    chrome_binary: Path string to the Chrome binary that should be used by
-      ChromeDriver.
-
-      If None then it will use the PATH to find a binary.
-    test_class: Name of the test class that should be run.
-      If this is set, then only the specified class will be executed
-    module: The module to load test cases from. This is relative to the tasks
-      package.
-    profile: Dict of profile data that acts as the master source for
-      validating autofill behaviour. If not specified then default profile data
-      will be used from testdata.profile_data.
-    debug: Whether debug output should be printed (False if not specified).
-  """
-  def __init__(self, user_data_dir, chrome_binary=None, test_class=None,
-               module='sites', profile=None, debug=False):
-    if profile is None:
-      profile = profile_data.DEFAULT
-
-    super(AutofillTestSuite, self).__init__()
-    self._test_class = test_class
-    self._profile = profile
-    self._debug = debug
-
-    module = 'tasks.%s' % module
-
-    try:
-      importlib.import_module(module)
-    except ImportError:
-      print 'Unable to load %s from tasks.' % module
-      raise
-
-    self._generate_tests(user_data_dir, chrome_binary)
-
-  def _generate_tests(self, user_data_dir, chrome_binary=None):
-    task_classes = AutofillTask.__subclasses__()
-    tests = []
-
-    if self._test_class:
-      for task in task_classes:
-        if task.__name__ == self._test_class:
-          test = AutofillTestCase(task, user_data_dir, self._profile,
-                                  chrome_binary=chrome_binary,
-                                  debug=self._debug)
-          self.addTest(test)
-          return
-
-      raise ValueError('Autofill Test \'%s\' could not be found.' %
-                       self._test_class)
-    else:
-      for task in task_classes:
-        tests.append(AutofillTestCase(task, user_data_dir, self._profile,
-                                      chrome_binary=chrome_binary,
-                                      debug=self._debug))
-
-    self.addTests(tests)
diff --git a/components/test/data/autofill/automated_integration/main.py b/components/test/data/autofill/automated_integration/main.py
deleted file mode 100755
index 5dd314d..0000000
--- a/components/test/data/autofill/automated_integration/main.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Autofill automated integration test runner
-
-Allows you to run integration test(s) for Autofill.
-At this time only a limited set of websites are supported.
-
-Requires:
-  - Selenium python bindings
-    http://selenium-python.readthedocs.org/
-
-  - ChromeDriver
-    https://sites.google.com/a/chromium.org/chromedriver/downloads
-    The ChromeDriver executable must be available on the search PATH.
-
-  - Chrome (>= 53)
-
-  - Write access to '/var/google/autofill/chrome_user_data'
-
-Instructions:
-  - Add tests to tasks/sites.py (or a new module in tasks/)
-  - Run main.py -h to view the available flags.
-    - All tests in tasks/sites.py will be run in the default chrome binary if
-      no flags are specified.
-"""
-
-import argparse
-import types
-import sys
-
-# Local Imports
-from autofill_test.suite import AutofillTestSuite
-from autofill_test.runner import AutofillTestRunner
-
-USER_DATA_DIR = '/var/google/autofill/chrome_user_data'
-
-
-def parse_args():
-  description = 'Allows you to run integration test(s) for Autofill.'
-  epilog = ('All tests in tasks/sites.py will be run in the default chrome '
-            'binary if no flags are specified. At this time only a limited '
-            'set of websites are supported.')
-
-  parser = argparse.ArgumentParser(description=description, epilog=epilog)
-  parser.add_argument('--user-data-dir', dest='user_data_dir', metavar='PATH',
-                      default=USER_DATA_DIR, help='chrome user data directory')
-  parser.add_argument('--chrome-binary', dest='chrome_binary', metavar='PATH',
-                      default=None, help='chrome binary location')
-  parser.add_argument('--module', default='sites', help='task module name')
-  parser.add_argument('--test', dest='test_class',
-                      help='name of a specific test to run')
-  parser.add_argument('-d', '--debug', action='store_true', default=False,
-                      help='print additional information, useful for debugging')
-
-  args = parser.parse_args()
-
-  args.debug = bool(args.debug)
-
-  return args
-
-
-def run(args):
-  if args.debug:
-    print 'Running with arguments: %s' % vars(args)
-
-  try:
-    test_suite = AutofillTestSuite(args.user_data_dir,
-                                   chrome_binary=args.chrome_binary,
-                                   test_class=args.test_class,
-                                   module=args.module, debug=args.debug)
-    verbosity = 2 if args.debug else 1
-    runner = AutofillTestRunner(verbosity=verbosity)
-    runner.run(test_suite)
-  except ImportError as e:
-    print 'Test Execution failed. %s' % str(e)
-  except Exception as e:
-    raise
-
-
-if __name__ == '__main__':
-  args = parse_args()
-  run(args)
diff --git a/components/test/data/autofill/automated_integration/task_flow.py b/components/test/data/autofill/automated_integration/task_flow.py
deleted file mode 100644
index a0e7b31..0000000
--- a/components/test/data/autofill/automated_integration/task_flow.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Chrome Autofill Task Flow
-
-Execute a set of autofill tasks in a fresh ChromeDriver instance that has been
-pre-loaded with some default profile.
-
-Requires:
-  - Selenium python bindings
-    http://selenium-python.readthedocs.org/
-
-  - ChromeDriver
-    https://sites.google.com/a/chromium.org/chromedriver/downloads
-    The ChromeDriver executable must be available on the search PATH.
-
-  - Chrome
-"""
-
-import abc
-from urlparse import urlparse
-import os
-import shutil
-from random import choice
-from string import ascii_lowercase
-
-from selenium import webdriver
-from selenium.common.exceptions import TimeoutException, WebDriverException
-from selenium.webdriver.chrome.options import Options
-
-
-class TaskFlow(object):
-  """Represents an executable set of Autofill Tasks.
-
-  Attributes:
-    profile: Dict of profile data that acts as the master source for
-      validating autofill behaviour.
-    debug: Whether debug output should be printed (False if not specified).
-  """
-  __metaclass__ = abc.ABCMeta
-  def __init__(self, profile, debug=False):
-    self.set_profile(profile)
-    self._debug = debug
-    self._running = False
-
-    self._tasks = self._generate_task_sequence()
-
-  def set_profile(self, profile):
-    """Validates |profile| before assigning it as the source of user data.
-
-    Args:
-      profile: Dict of profile data that acts as the master source for
-        validating autofill behaviour.
-
-    Raises:
-      ValueError: The |profile| dict provided is missing required keys
-    """
-    if not isinstance(profile, dict):
-      raise ValueError('profile must be a a valid dictionary');
-
-    self._profile = profile
-
-  def run(self, user_data_dir, chrome_binary=None):
-    """Generates and executes a sequence of chrome driver tasks.
-
-    Args:
-      user_data_dir: Path string for the writable directory in which profiles
-        should be stored.
-      chrome_binary: Path string to the Chrome binary that should be used by
-        ChromeDriver.
-
-        If None then it will use the PATH to find a binary.
-
-    Raises:
-      RuntimeError: Running the TaskFlow was attempted while it's already
-        running.
-      Exception: Any failure encountered while running the tests
-    """
-    if self._running:
-      raise RuntimeError('Cannot run TaskFlow when already running')
-
-    self._running = True
-
-    self._run_tasks(user_data_dir, chrome_binary=chrome_binary)
-
-    self._running = False
-
-  @abc.abstractmethod
-  def _generate_task_sequence(self):
-    """Generates a set of executable tasks that will be run in ChromeDriver.
-
-    Note: Subclasses must implement this method.
-
-    Raises:
-      NotImplementedError: Subclass did not implement the method
-
-    Returns:
-      A list of AutofillTask instances that are to be run in ChromeDriver.
-
-      These tasks are to be run in order.
-    """
-    raise NotImplementedError()
-
-  def _run_tasks(self, user_data_dir, chrome_binary=None):
-    """Runs the internal set of tasks in a fresh ChromeDriver instance.
-
-    Args:
-      user_data_dir: Path string for the writable directory in which profiles
-        should be stored.
-      chrome_binary: Path string to the Chrome binary that should be used by
-        ChromeDriver.
-
-        If None then it will use the PATH to find a binary.
-
-    Raises:
-      Exception: Any failure encountered while running the tests
-    """
-    driver = self._get_driver(user_data_dir, chrome_binary=chrome_binary)
-    try:
-      for task in self._tasks:
-        task.run(driver)
-    finally:
-      driver.quit()
-      shutil.rmtree(self._profile_dir_dst)
-
-  def _get_driver(self, user_data_dir, profile_name=None, chrome_binary=None,
-                  chromedriver_binary='chromedriver'):
-    """Spin up a ChromeDriver instance that uses a given set of user data.
-
-    Generates a temporary profile data directory using a local set of test data.
-
-    Args:
-      user_data_dir: Path string for the writable directory in which profiles
-        should be stored.
-      profile_name: Name of the profile data directory to be created/used in
-        user_data_dir.
-
-        If None then an eight character name will be generated randomly.
-
-        This directory will be removed after the task flow completes.
-      chrome_binary: Path string to the Chrome binary that should be used by
-        ChromeDriver.
-
-        If None then it will use the PATH to find a binary.
-
-    Returns: The generated Chrome Driver instance.
-    """
-    options = Options()
-
-    if profile_name is None:
-      profile_name = ''.join(choice(ascii_lowercase) for i in range(8))
-
-    options.add_argument('--profile-directory=%s' % profile_name)
-
-    full_path = os.path.realpath(__file__)
-    path, filename = os.path.split(full_path)
-    profile_dir_src = os.path.join(path, 'testdata', 'Default')
-    self._profile_dir_dst = os.path.join(user_data_dir, profile_name)
-    self._copy_tree(profile_dir_src, self._profile_dir_dst)
-
-    if chrome_binary is not None:
-      options.binary_location = chrome_binary
-
-    options.add_argument('--user-data-dir=%s' % user_data_dir)
-    options.add_argument('--show-autofill-type-predictions')
-
-    service_args = []
-
-    driver = webdriver.Chrome(executable_path=chromedriver_binary,
-                              chrome_options=options,
-                              service_args=service_args)
-    driver.set_page_load_timeout(15)  # seconds
-    return driver
-
-  def _copy_tree(self, src, dst):
-    """Recursively copy a directory tree.
-
-    If the destination directory does not exist then it will be created for you.
-    Doesn't overwrite newer existing files.
-
-    Args:
-      src: Path to the target source directory. It must exist.
-      dst: Path to the target destination directory. Permissions to create the
-        the directory (if necessary) and modify it's contents.
-    """
-    if not os.path.exists(dst):
-      os.makedirs(dst)
-    for item in os.listdir(src):
-      src_item = os.path.join(src, item)
-      dst_item = os.path.join(dst, item)
-      if os.path.isdir(src_item):
-        self._copy_tree(src_item, dst_item)
-      elif (not os.path.exists(dst_item) or
-        os.stat(src_item).st_mtime - os.stat(dst_item).st_mtime > 1):
-        # Copy a file if it doesn't already exist, or if existing one is older.
-        shutil.copy2(src_item, dst_item)
diff --git a/components/test/data/autofill/automated_integration/tasks/__init__.py b/components/test/data/autofill/automated_integration/tasks/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/components/test/data/autofill/automated_integration/tasks/__init__.py
+++ /dev/null
diff --git a/components/test/data/autofill/automated_integration/tasks/sites.py b/components/test/data/autofill/automated_integration/tasks/sites.py
deleted file mode 100644
index 7229bba..0000000
--- a/components/test/data/autofill/automated_integration/tasks/sites.py
+++ /dev/null
@@ -1,128 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from autofill_task.autofill_task import AutofillTask
-
-# pylint: disable=g-multiple-import
-# pylint: disable=unused-import
-from autofill_task.actions import (SetContext, Open, Click, Type, Wait, Select,
-                                   ByID, ByClassName, ByCssSelector, Screenshot,
-                                   ByXPath, ValidateFields, TriggerAutofill)
-
-from autofill_task.generator import Generator
-
-
-class TestNeweggComGuestCheckout(AutofillTask):
-  def _create_script(self):
-    self.script = [
-        Open('http://www.newegg.com/Product/Product.aspx?Item=N82E16823126097'),
-        Click(ByXPath('//*[@id="landingpage-cart"]/div/div[2]/button['
-                      'contains(., \'ADD TO CART\')]')),
-        Click(ByXPath('//a[contains(., \'View Shopping Cart\')]'), True),
-        Click(ByXPath('//a[contains(., \'Secure Checkout\')]')),
-        Click(ByXPath('//a[contains(., \'CONTINUE AS A GUEST\')]'), True),
-        TriggerAutofill(ByXPath('//*[@id="SFirstName"]'), 'NAME_FIRST'),
-        ValidateFields([
-            (ByXPath('//*[@id="SFirstName"]'), 'NAME_FIRST'),
-            (ByXPath('//*[@id="SLastName"]'), 'NAME_LAST'),
-            (ByXPath('//*[@id="SAddress1"]'), 'ADDRESS_HOME_LINE1'),
-            (ByXPath('//*[@id="SAddress2"]'), 'ADDRESS_HOME_LINE2'),
-            (ByXPath('//*[@id="SCity"]'), 'ADDRESS_HOME_CITY'),
-            (ByXPath('//*[@id="SState_Option_USA"]'), 'ADDRESS_HOME_STATE',
-             'CA'),
-            (ByXPath('//*[@id="SZip"]'), 'ADDRESS_HOME_ZIP', '94035-____'),
-            (ByXPath('//*[@id="ShippingPhone"]'), 'PHONE_HOME_CITY_AND_NUMBER',
-             '(650) 670-1234 x__________'),
-            (ByXPath('//*[@id="email"]'), 'EMAIL_ADDRESS'),
-        ]),
-    ]
-
-
-class TestGamestopCom(AutofillTask):
-  def _create_script(self):
-    self.script = [
-        Open('http://www.gamestop.com/ps4/consoles/playstation-4-500gb-system-'
-             'white/118544'),
-        # First redirects you to the canadian site if run internationally
-        Open('http://www.gamestop.com/ps4/consoles/playstation-4-500gb-system-'
-             'white/118544'),
-        Click(ByXPath('//*[@id="mainContentPlaceHolder_dynamicContent_ctl00_'
-                      'RepeaterRightColumnLayouts_RightColumnPlaceHolder_0_'
-                      'ctl00_0_ctl00_0_StandardPlaceHolder_2_ctl00_2_'
-                      'rptBuyBoxes_2_lnkAddToCart_0"]')),
-        Click(ByXPath('//*[@id="checkoutButton"]')),
-        Click(ByXPath('//*[@id="cartcheckoutbtn"]')),
-        Click(ByXPath('//*[@id="buyasguest"]')),
-        TriggerAutofill(ByXPath('//*[@id="ShipTo_FirstName"]'), 'NAME_FIRST'),
-        ValidateFields([
-            (ByXPath('//*[@id="ShipTo_CountryCode"]'), 'ADDRESS_HOME_COUNTRY',
-             'US'),
-            (ByXPath('//*[@id="ShipTo_FirstName"]'), 'NAME_FIRST'),
-            (ByXPath('//*[@id="ShipTo_LastName"]'), 'NAME_LAST'),
-            (ByXPath('//*[@id="ShipTo_Line1"]'), 'ADDRESS_HOME_LINE1'),
-            (ByXPath('//*[@id="ShipTo_Line2"]'), 'ADDRESS_HOME_LINE2'),
-            (ByXPath('//*[@id="ShipTo_City"]'), 'ADDRESS_HOME_CITY'),
-            (ByXPath('//*[@id="USStates"]'), 'ADDRESS_HOME_STATE', 'CA'),
-            (ByXPath('//*[@id="ShipTo_PostalCode"]'), 'ADDRESS_HOME_ZIP'),
-            (ByXPath('//*[@id="ShipTo_PhoneNumber"]'),
-             'PHONE_HOME_CITY_AND_NUMBER'),
-            (ByXPath('//*[@id="ShipTo_EmailAddress"]'), 'EMAIL_ADDRESS'),
-        ])
-    ]
-
-
-class TestLowesCom(AutofillTask):
-  def _create_script(self):
-    self.script = [
-        Open('http://www.lowes.com/pd/Weber-Original-Kettle-22-in-Black-'
-             'Porcelain-Enameled-Kettle-Charcoal-Grill/3055249'),
-        Type(ByXPath('//*[@id="zipcode-input"]'),
-             self.profile_data('ADDRESS_HOME_ZIP'), True),
-        Click(ByXPath('//button[contains(., \'Ok\')]'), True),
-        Click(ByXPath('//*[@id="storeList"]/li[1]/div/div[2]/button['
-                      'contains(., \'Shop this store\')]'), True),
-        Wait(3),
-        Click(ByXPath('//button[contains(., \'Add To Cart\')]')),
-        Click(ByXPath('//a[contains(., \'View Cart\')]')),
-        Click(ByXPath('//*[@id="LDshipModeId_1"]')),
-        Click(ByXPath('//*[@id="ShopCartForm"]/div[2]/div[2]/a[contains(.,'
-                      ' \'Start Secure Checkout\')]')),
-        Click(ByXPath('//*[@id="login-container"]/div[2]/div/div/div/a['
-                      'contains(., \'Check Out\')]')),
-        TriggerAutofill(ByXPath('//*[@id="fname"]'), 'NAME_FIRST'),
-        ValidateFields([
-            (ByXPath('//*[@id="fname"]'), 'NAME_FIRST'),
-            (ByXPath('//*[@id="lname"]'), 'NAME_LAST'),
-            (ByXPath('//*[@id="company-name"]'), 'COMPANY_NAME'),
-            (ByXPath('//*[@id="address-1"]'), 'ADDRESS_HOME_LINE1'),
-            (ByXPath('//*[@id="address-2"]'), 'ADDRESS_HOME_LINE2'),
-            (ByXPath('//*[@id="city"]'), 'ADDRESS_HOME_CITY'),
-            (ByXPath('//*[@id="state"]'), 'ADDRESS_HOME_STATE', 'CA'),
-            (ByXPath('//*[@id="zip"]'), 'ADDRESS_HOME_ZIP'),
-        ]),
-        Click(ByXPath('//*[@id="revpay_com_order"]')),
-        Wait(1), # Buttons with the same xPath exists on both pages
-        Click(ByXPath('//*[@id="revpay_com_order"]')),
-        Wait(1), # Buttons with the same xPath exists on both pages
-        TriggerAutofill(ByXPath('//*[@name="cardNumber"]'),
-                        'CREDIT_CARD_NUMBER'),
-        Type(ByXPath('//*[@id="s-code"]'),
-             self.profile_data('CREDIT_CARD_VERIFICATION_CODE')),
-        Type(ByXPath('//*[@id="billing-address-phone1"]'),
-             self.profile_data('PHONE_HOME_CITY_AND_NUMBER')),
-        Type(ByXPath('//*[@id="billingEmailAddress"]'),
-             self.profile_data('EMAIL_ADDRESS')),
-        ValidateFields([
-            (ByXPath('//*[@id="checkout-card-type"]'), 'CREDIT_CARD_TYPE'),
-            (ByXPath('//*[@name="cardNumber"]'), 'CREDIT_CARD_NUMBER'),
-            (ByXPath('//*[@id="s-code"]'), 'CREDIT_CARD_VERIFICATION_CODE'),
-            (ByXPath('//*[@id="expiration-month"]'), 'CREDIT_CARD_EXP_MONTH'),
-            (ByXPath('//*[@id="expiration-year"]'),
-             'CREDIT_CARD_EXP_4_DIGIT_YEAR'),
-            (ByXPath('//*[@id="billing-address-phone1"]'),
-             'PHONE_HOME_CITY_AND_NUMBER', '(650) 670-1234'),
-            (ByXPath('//*[@id="billingEmailAddress"]'), 'EMAIL_ADDRESS'),
-        ]),
-        Click(ByXPath('//*[@id="revpay_com_order"]'))
-    ]
diff --git a/components/test/data/autofill/automated_integration/testdata/Default/Preferences b/components/test/data/autofill/automated_integration/testdata/Default/Preferences
deleted file mode 100644
index 9956a29..0000000
--- a/components/test/data/autofill/automated_integration/testdata/Default/Preferences
+++ /dev/null
@@ -1 +0,0 @@
-{"autofill":{"profile_use_dates_fixed":true}}
diff --git a/components/test/data/autofill/automated_integration/testdata/Default/Web Data b/components/test/data/autofill/automated_integration/testdata/Default/Web Data
deleted file mode 100644
index c411920..0000000
--- a/components/test/data/autofill/automated_integration/testdata/Default/Web Data
+++ /dev/null
Binary files differ
diff --git a/components/test/data/autofill/automated_integration/testdata/README b/components/test/data/autofill/automated_integration/testdata/README
deleted file mode 100644
index 069f514..0000000
--- a/components/test/data/autofill/automated_integration/testdata/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This data is used to populate the generated user data directory with just enough
-files to add a functioning autofill profile.
diff --git a/components/test/data/autofill/automated_integration/testdata/__init__.py b/components/test/data/autofill/automated_integration/testdata/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/components/test/data/autofill/automated_integration/testdata/__init__.py
+++ /dev/null
diff --git a/components/test/data/autofill/automated_integration/testdata/profile_data.py b/components/test/data/autofill/automated_integration/testdata/profile_data.py
deleted file mode 100644
index 471eb40d..0000000
--- a/components/test/data/autofill/automated_integration/testdata/profile_data.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Autofill expected data by field type. This matches the default profile.
-"""
-
-DEFAULT = {
-    # Personal Information categorization types.
-    'NAME_FIRST': 'Donald',
-    'NAME_MIDDLE': 'Craig',
-    'NAME_LAST': 'Figgleburg',
-    'NAME_MIDDLE_INITIAL': 'C',
-    'NAME_FULL': 'Donald Craig Figgleburg',
-    'NAME_SUFFIX': '',
-    'EMAIL_ADDRESS': 'donald@figgleburg.com',
-    'PHONE_HOME_NUMBER': '6701234',
-    'PHONE_HOME_CITY_CODE': '650',
-    'PHONE_HOME_COUNTRY_CODE': '+1',
-    'PHONE_HOME_CITY_AND_NUMBER': '6506701234',
-    'PHONE_HOME_WHOLE_NUMBER': '+16506701234',
-    'ADDRESS_HOME_LINE1': '314 Oceanwalk Rd.',
-    'ADDRESS_HOME_LINE2': 'Apt. 4',
-    'ADDRESS_HOME_APPT_NUM': '4',
-    'ADDRESS_HOME_CITY': 'Mountain View',
-    'ADDRESS_HOME_STATE': 'California',
-    'ADDRESS_HOME_ZIP': '94035',
-    'ADDRESS_HOME_COUNTRY': 'United States',
-    'CREDIT_CARD_NAME': 'Donald Figgleburg',
-    'CREDIT_CARD_NUMBER': '5432123498764567',
-    'CREDIT_CARD_EXP_MONTH': '05',
-    'CREDIT_CARD_EXP_2_DIGIT_YEAR': '21',
-    'CREDIT_CARD_EXP_4_DIGIT_YEAR': '2021',
-    'CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR': '05/21',
-    'CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR': '05/2021',
-    'CREDIT_CARD_TYPE': '',
-    'CREDIT_CARD_VERIFICATION_CODE': '',
-    'COMPANY_NAME': 'Frtizerg Inc.',
-
-    # Generic fieldtype having default value to use, used only by autocheckout
-    # experiment. These field types exist for select merchant pages. Field
-    # mappings for these pages are generated by autocheckout's buildstorage
-    # script.
-    'FIELD_WITH_DEFAULT_VALUE': '',
-
-    # Includes of the lines of a street address, including newlines, e.g.
-    #   123 Main Street,
-    #   Apt. #42
-    'ADDRESS_HOME_STREET_ADDRESS': '314 Oceanwalk Rd.\nApt. 4',
-
-    'ACCOUNT_CREATION_PASSWORD': '',
-
-    # The third line of the street address.
-    'ADDRESS_HOME_LINE3': '',
-}
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 4828b3e..095477a 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -154,6 +154,14 @@
     BeginFrameSource* begin_frame_source) {
   if (begin_frame_source_ && added_frame_observer_) {
     begin_frame_source_->RemoveObserver(this);
+    // When detaching from source, CompositorFrameSinkClient needs to know that
+    // there are no more OnBeginFrame. Otherwise, client in renderer could wait
+    // OnBeginFrame forever. e.g., crbug.com/1335000.
+    // OnBeginFrameSourcePausedChanged(false) is not handled here because it's
+    // handled in AddObserver() depending on current status of begin frame
+    // source.
+    if (!begin_frame_source)
+      OnBeginFrameSourcePausedChanged(true);
     added_frame_observer_ = false;
   }
 
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 88b4436..54e4a91 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -930,7 +930,7 @@
 void GpuDataManagerImplPrivate::RequestMojoMediaVideoCapabilities() {
   base::OnceClosure task = base::BindOnce([]() {
     auto media_interface_proxy =
-        std::make_unique<FramelessMediaInterfaceProxy>();
+        std::make_unique<FramelessMediaInterfaceProxy>(nullptr);
 
     mojo::PendingRemote<media::mojom::VideoDecoder> pending_remote_decoder;
     media_interface_proxy->CreateVideoDecoder(
@@ -946,13 +946,15 @@
     DCHECK(remote_decoder_ptr);
     remote_decoder_ptr->GetSupportedConfigs(base::BindOnce(
         [](mojo::Remote<media::mojom::VideoDecoder> /* remote_decoder */,
+           std::unique_ptr<
+               FramelessMediaInterfaceProxy> /* media_interface_proxy */,
            const media::SupportedVideoDecoderConfigs& configs,
            media::VideoDecoderType /* decoder_type */) {
           GpuDataManagerImpl* manager = GpuDataManagerImpl::GetInstance();
           DCHECK(manager);
           manager->UpdateMojoMediaVideoCapabilities(configs);
         },
-        std::move(remote_decoder)));
+        std::move(remote_decoder), std::move(media_interface_proxy)));
   });
 
   GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(task));
diff --git a/content/browser/media/frameless_media_interface_proxy.cc b/content/browser/media/frameless_media_interface_proxy.cc
index fed15bd0c..a3d30dbf 100644
--- a/content/browser/media/frameless_media_interface_proxy.cc
+++ b/content/browser/media/frameless_media_interface_proxy.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "content/public/browser/media_service.h"
+#include "content/public/browser/render_process_host.h"
 #include "media/base/cdm_context.h"
 #include "media/mojo/mojom/media_service.mojom.h"
 #include "media/mojo/mojom/renderer_extensions.mojom.h"
@@ -22,7 +23,9 @@
 
 namespace content {
 
-FramelessMediaInterfaceProxy::FramelessMediaInterfaceProxy() {
+FramelessMediaInterfaceProxy::FramelessMediaInterfaceProxy(
+    RenderProcessHost* render_process_host)
+    : render_process_host_(render_process_host) {
   DVLOG(1) << __func__;
 }
 
@@ -66,12 +69,22 @@
       oop_video_decoder;
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   if (base::FeatureList::IsEnabled(media::kUseOutOfProcessVideoDecoding)) {
-    // TODO(b/195769334): for now, we're using the same
-    // StableVideoDecoderFactory. However, we should be using a separate
-    // StableVideoDecoderFactory for each client (i.e., different renderers
-    // should use different video decoder processes).
-    GetStableVideoDecoderFactory().CreateStableVideoDecoder(
-        oop_video_decoder.InitWithNewPipeAndPassReceiver());
+    if (!render_process_host_) {
+      if (!stable_vd_factory_remote_.is_bound()) {
+        LaunchStableVideoDecoderFactory(
+            stable_vd_factory_remote_.BindNewPipeAndPassReceiver());
+        stable_vd_factory_remote_.reset_on_disconnect();
+      }
+
+      if (!stable_vd_factory_remote_.is_bound())
+        return;
+
+      stable_vd_factory_remote_->CreateStableVideoDecoder(
+          oop_video_decoder.InitWithNewPipeAndPassReceiver());
+    } else {
+      render_process_host_->CreateStableVideoDecoder(
+          oop_video_decoder.InitWithNewPipeAndPassReceiver());
+    }
   }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   factory->CreateVideoDecoder(std::move(receiver),
diff --git a/content/browser/media/frameless_media_interface_proxy.h b/content/browser/media/frameless_media_interface_proxy.h
index f2c06933..c6fb18a 100644
--- a/content/browser/media/frameless_media_interface_proxy.h
+++ b/content/browser/media/frameless_media_interface_proxy.h
@@ -19,8 +19,14 @@
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "media/mojo/mojom/stable/stable_video_decoder.mojom.h"
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 namespace content {
 
+class RenderProcessHost;
+
 // This implements the media::mojom::InterfaceFactory interface for a
 // RenderProcessHostImpl. It does not support creating services that require a
 // frame context (ie. CDMs and renderers).
@@ -30,7 +36,7 @@
 class FramelessMediaInterfaceProxy final
     : public media::mojom::InterfaceFactory {
  public:
-  FramelessMediaInterfaceProxy();
+  explicit FramelessMediaInterfaceProxy(RenderProcessHost* render_process_host);
 
   FramelessMediaInterfaceProxy(const FramelessMediaInterfaceProxy&) = delete;
   FramelessMediaInterfaceProxy& operator=(const FramelessMediaInterfaceProxy&) =
@@ -93,6 +99,24 @@
   // Connections to the renderer.
   mojo::ReceiverSet<media::mojom::InterfaceFactory> receivers_;
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  // Connection to the StableVideoDecoderFactory that lives in a utility
+  // process. This is only used for out-of-process video decoding and only when
+  // the FramelessMediaInterfaceProxy is created without a RenderProcessHost
+  // (e.g., to get the supported video decoder configurations). Note that we
+  // make this a member instead of a local variable inside CreateVideoDecoder()
+  // in order to keep the video decoder process alive for the lifetime of the
+  // FramelessMediaInterfaceProxy.
+  mojo::Remote<media::stable::mojom::StableVideoDecoderFactory>
+      stable_vd_factory_remote_;
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
+  // FramelessMediaInterfaceProxy is fully owned by the RenderProcessHostImpl,
+  // and the latter never gives up that ownership. Therefore,
+  // *|render_process_host_| will never be destroyed before it's used by
+  // *|this|.
+  const raw_ptr<RenderProcessHost> render_process_host_ = nullptr;
+
   THREAD_CHECKER(thread_checker_);
 };
 
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc
index fff49eb..83c1764 100644
--- a/content/browser/media/media_interface_proxy.cc
+++ b/content/browser/media/media_interface_proxy.cc
@@ -288,11 +288,7 @@
       oop_video_decoder;
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
   if (base::FeatureList::IsEnabled(media::kUseOutOfProcessVideoDecoding)) {
-    // TODO(b/195769334): for now, we're using the same
-    // StableVideoDecoderFactory. However, we should be using a separate
-    // StableVideoDecoderFactory for each client (i.e., different renderers
-    // should use different video decoder processes).
-    GetStableVideoDecoderFactory().CreateStableVideoDecoder(
+    render_frame_host().GetProcess()->CreateStableVideoDecoder(
         oop_video_decoder.InitWithNewPipeAndPassReceiver());
   }
 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
diff --git a/content/browser/media/stable_video_decoder_factory.cc b/content/browser/media/stable_video_decoder_factory.cc
index bb866f3..65727e35e 100644
--- a/content/browser/media/stable_video_decoder_factory.cc
+++ b/content/browser/media/stable_video_decoder_factory.cc
@@ -4,38 +4,24 @@
 
 #include "content/public/browser/stable_video_decoder_factory.h"
 
-#include "base/threading/sequence_local_storage_slot.h"
 #include "build/chromeos_buildflags.h"
 #include "content/public/browser/service_process_host.h"
 #include "media/mojo/mojom/stable/stable_video_decoder.mojom.h"
-#include "mojo/public/cpp/bindings/remote.h"
 
 namespace content {
 
-media::stable::mojom::StableVideoDecoderFactory&
-GetStableVideoDecoderFactory() {
-  // NOTE: We use sequence-local storage to limit the lifetime of this Remote to
-  // that of the UI-thread sequence. This ensures that the Remote is destroyed
-  // when the task environment is torn down and reinitialized, e.g. between unit
-  // tests.
-  static base::SequenceLocalStorageSlot<
-      mojo::Remote<media::stable::mojom::StableVideoDecoderFactory>>
-      remote_slot;
-  auto& remote = remote_slot.GetOrCreateValue();
-  remote.reset_on_disconnect();
-  [[maybe_unused]] auto receiver = remote.BindNewPipeAndPassReceiver();
-  if (!remote) {
+void LaunchStableVideoDecoderFactory(
+    mojo::PendingReceiver<media::stable::mojom::StableVideoDecoderFactory>
+        receiver) {
 #if BUILDFLAG(IS_CHROMEOS_LACROS)
-    // TODO(pmolinalopez): for LaCrOS, we need to use crosapi to establish a
-    // StableVideoDecoderFactory connection to ash-chrome.
-    NOTIMPLEMENTED();
+  // TODO(pmolinalopez): for LaCrOS, we need to use crosapi to establish a
+  // StableVideoDecoderFactory connection to ash-chrome.
+  NOTIMPLEMENTED();
 #else
-    ServiceProcessHost::Launch(
-        std::move(receiver),
-        ServiceProcessHost::Options().WithDisplayName("Video Decoder").Pass());
+  ServiceProcessHost::Launch(
+      std::move(receiver),
+      ServiceProcessHost::Options().WithDisplayName("Video Decoder").Pass());
 #endif
-  }
-  return *remote.get();
 }
 
 }  // namespace content
diff --git a/content/browser/net/sandboxed_socket_broker_browsertest.cc b/content/browser/net/sandboxed_socket_broker_browsertest.cc
new file mode 100644
index 0000000..0b0f3f7
--- /dev/null
+++ b/content/browser/net/sandboxed_socket_broker_browsertest.cc
@@ -0,0 +1,215 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/feature_list.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "content/browser/net/socket_broker_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/network_service_util.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "net/base/ip_endpoint.h"
+#include "net/socket/tcp_server_socket.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "sandbox/features.h"
+#include "sandbox/policy/features.h"
+#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+#if BUILDFLAG(IS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
+namespace content {
+namespace {
+
+const char kTestResponse[] = "hello socket broker";
+
+class SandboxedSocketBrokerBrowserTest : public ContentBrowserTest {
+ public:
+  SandboxedSocketBrokerBrowserTest() {
+#if BUILDFLAG(IS_ANDROID)
+    // On older Android the Connect callback is not called with the featurelist
+    // enabled. Since it is not strictly necessary to test socket brokering core
+    // functionality with the featurelist we won't enable it on Android versions
+    // prior to R.
+    const int sdk_version = base::android::BuildInfo::GetInstance()->sdk_int();
+    if (sdk_version >= base::android::SdkVersion::SDK_VERSION_R) {
+      std::vector<base::Feature> enabled_features = {
+          sandbox::policy::features::kNetworkServiceSandbox,
+      };
+      scoped_feature_list_.InitWithFeatures(
+          enabled_features, {features::kNetworkServiceInProcess});
+    } else {
+      check_sandbox_ = false;
+    }
+#else
+    std::vector<base::Feature> enabled_features = {
+#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_FUCHSIA)
+      // Network Service Sandboxing is unconditionally enabled on these
+      // platforms.
+      sandbox::policy::features::kNetworkServiceSandbox,
+#endif
+    };
+    scoped_feature_list_.InitWithFeatures(enabled_features,
+                                          {features::kNetworkServiceInProcess});
+#endif
+  }
+
+  void SetUp() override {
+#if BUILDFLAG(IS_WIN)
+    // TODO(https://crbug.com/1311014): Run these tests on Windows once the
+    // broker can open and release sockets.
+    GTEST_SKIP();
+#else
+    if (check_sandbox_) {
+      ASSERT_TRUE(IsOutOfProcessNetworkService());
+      ASSERT_TRUE(sandbox::policy::features::IsNetworkSandboxEnabled());
+    }
+
+    embedded_test_server_.RegisterRequestHandler(
+        base::BindRepeating(&SandboxedSocketBrokerBrowserTest::HandleRequest,
+                            base::Unretained(this)));
+
+    ASSERT_TRUE(embedded_test_server_.InitializeAndListen());
+    ContentBrowserTest::SetUp();
+#endif
+  }
+
+#if !BUILDFLAG(IS_WIN)
+  void SetUpOnMainThread() override {
+    embedded_test_server_.StartAcceptingConnections();
+  }
+#endif
+
+  std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
+      const net::test_server::HttpRequest& request) {
+    GURL absolute_url = embedded_test_server_.GetURL(request.relative_url);
+    if (absolute_url.path() != "/test")
+      return nullptr;
+
+    auto http_response =
+        std::make_unique<net::test_server::BasicHttpResponse>();
+    http_response->set_code(net::HTTP_OK);
+    http_response->set_content(kTestResponse);
+    http_response->set_content_type("text/plain");
+    return http_response;
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+  net::test_server::EmbeddedTestServer embedded_test_server_;
+  bool check_sandbox_ = true;
+};
+
+void OnConnected(base::OnceClosure quit_closure,
+                 int result,
+                 const absl::optional<net::IPEndPoint>& local_addr,
+                 const absl::optional<net::IPEndPoint>& peer_addr,
+                 mojo::ScopedDataPipeConsumerHandle receive_stream,
+                 mojo::ScopedDataPipeProducerHandle send_stream) {
+  base::ScopedClosureRunner closure_runner(std::move(quit_closure));
+  ASSERT_EQ(result, net::OK);
+  const std::string request = "GET /test HTTP/1.0\r\n\r\n";
+  ASSERT_TRUE(BlockingCopyFromString(request, std::move(send_stream)));
+  std::string response;
+  ASSERT_TRUE(BlockingCopyToString(std::move(receive_stream), &response));
+  LOG(ERROR) << response;
+  EXPECT_NE(response.find(kTestResponse), std::string::npos);
+}
+
+// Creates a TCPConnectedSocket that attempts one GET request to
+// `embedded_test_server`.
+void RunTcpEndToEndTest(
+    network::mojom::NetworkContext* network_context,
+    net::test_server::EmbeddedTestServer& embedded_test_server) {
+  mojo::PendingRemote<network::mojom::TCPConnectedSocket>
+      tcp_connected_socket_remote;
+  net::AddressList addr;
+  ASSERT_TRUE(embedded_test_server.GetAddressList(&addr));
+
+  base::RunLoop run_loop;
+  network_context->CreateTCPConnectedSocket(
+      absl::nullopt, addr, nullptr,
+      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+      tcp_connected_socket_remote.InitWithNewPipeAndPassReceiver(),
+      mojo::NullRemote(), base::BindOnce(&OnConnected, run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
+IN_PROC_BROWSER_TEST_F(SandboxedSocketBrokerBrowserTest,
+                       TcpEndToEndDefaultContext) {
+  network::mojom::NetworkContext* network_context =
+      shell()
+          ->web_contents()
+          ->GetBrowserContext()
+          ->GetDefaultStoragePartition()
+          ->GetNetworkContext();
+  ASSERT_TRUE(network_context);
+
+  RunTcpEndToEndTest(network_context, embedded_test_server_);
+}
+
+// Implementation of network::mojom::SocketBroker that tracks the number of
+// times CreateTcpSocket has been called.
+class CountingSocketBrokerImpl : public SocketBrokerImpl {
+ public:
+  void CreateTcpSocket(net::AddressFamily address_family,
+                       CreateTcpSocketCallback callback) override {
+    ++tcp_socket_count_;
+    SocketBrokerImpl::CreateTcpSocket(address_family, std::move(callback));
+  }
+  int tcp_socket_count() { return tcp_socket_count_; }
+
+ private:
+  int tcp_socket_count_ = 0;
+};
+
+IN_PROC_BROWSER_TEST_F(SandboxedSocketBrokerBrowserTest,
+                       TcpEndToEndBrokeredContext) {
+  CountingSocketBrokerImpl socket_broker;
+  network::mojom::NetworkContextParamsPtr network_context_params =
+      network::mojom::NetworkContextParams::New();
+  network_context_params->socket_broker = socket_broker.BindNewRemote();
+  auto file_paths = network::mojom::NetworkContextFilePaths::New();
+  base::FilePath context_path =
+      shell()->web_contents()->GetBrowserContext()->GetPath().Append(
+          FILE_PATH_LITERAL("TestContext"));
+  file_paths->data_directory = context_path.Append(FILE_PATH_LITERAL("Data"));
+  file_paths->unsandboxed_data_path = context_path;
+  file_paths->trigger_migration = true;
+  network_context_params->file_paths = std::move(file_paths);
+  network_context_params->cert_verifier_params = GetCertVerifierParams(
+      cert_verifier::mojom::CertVerifierCreationParams::New());
+  network_context_params->http_cache_enabled = true;
+  network_context_params->http_cache_directory =
+      shell()
+          ->web_contents()
+          ->GetBrowserContext()
+          ->GetPath()
+          .Append(FILE_PATH_LITERAL("TestContext"))
+          .Append(FILE_PATH_LITERAL("Cache"));
+  mojo::Remote<network::mojom::NetworkContext> network_context;
+  CreateNetworkContextInNetworkService(
+      network_context.BindNewPipeAndPassReceiver(),
+      std::move(network_context_params));
+
+  RunTcpEndToEndTest(network_context.get(), embedded_test_server_);
+  EXPECT_EQ(socket_broker.tcp_socket_count(), 1);
+}
+
+}  // namespace
+}  // namespace content
diff --git a/content/browser/net/socket_broker_impl.cc b/content/browser/net/socket_broker_impl.cc
index 5ac6c4a5..5db9ee7 100644
--- a/content/browser/net/socket_broker_impl.cc
+++ b/content/browser/net/socket_broker_impl.cc
@@ -31,4 +31,11 @@
 #endif
 }
 
+mojo::PendingRemote<network::mojom::SocketBroker>
+SocketBrokerImpl::BindNewRemote() {
+  mojo::PendingRemote<network::mojom::SocketBroker> pending_remote;
+  receivers_.Add(this, pending_remote.InitWithNewPipeAndPassReceiver());
+  return pending_remote;
+}
+
 }  // namespace content
diff --git a/content/browser/net/socket_broker_impl.h b/content/browser/net/socket_broker_impl.h
index 60d0e24..bbb1f4b6 100644
--- a/content/browser/net/socket_broker_impl.h
+++ b/content/browser/net/socket_broker_impl.h
@@ -14,6 +14,9 @@
 
 // Implementation of SocketBroker interface. Creates new sockets and sends them
 // to the network sandbox via mojo.
+// TODO(liza): IPCs are currently handled in the UI thread since NetworkContext
+// is created in that thread. The IPCs should be dispatched to a different
+// sequence.
 class CONTENT_EXPORT SocketBrokerImpl : public network::mojom::SocketBroker {
  public:
   explicit SocketBrokerImpl();
@@ -26,6 +29,10 @@
   void CreateTcpSocket(net::AddressFamily address_family,
                        CreateTcpSocketCallback callback) override;
 
+  // Returns a mojo::PendingRemote to this instance. Adds a receiver to
+  // `receivers_`.
+  mojo::PendingRemote<network::mojom::SocketBroker> BindNewRemote();
+
  private:
   mojo::ReceiverSet<network::mojom::SocketBroker> receivers_;
 };
diff --git a/content/browser/net/socket_broker_impl_unittest.cc b/content/browser/net/socket_broker_impl_unittest.cc
new file mode 100644
index 0000000..7841c40
--- /dev/null
+++ b/content/browser/net/socket_broker_impl_unittest.cc
@@ -0,0 +1,51 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "socket_broker_impl.h"
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/base/address_family.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/net_errors.h"
+#include "net/socket/socket_descriptor.h"
+#include "net/test/gtest_util.h"
+#include "services/network/public/mojom/socket_broker.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+void DidCompleteCreateTest(base::RunLoop* run_loop,
+                           mojo::PlatformHandle fd,
+                           int rv) {
+// TODO(https://crbug.com/1311014): Remove ifdef and expect a result of net::OK
+// on Windows.
+#if BUILDFLAG(IS_WIN)
+  EXPECT_EQ(rv, net::ERR_FAILED);
+#else
+  EXPECT_NE(fd.ReleaseFD(), net::kInvalidSocket);
+  EXPECT_EQ(rv, net::OK);
+#endif
+
+  run_loop->Quit();
+}
+
+TEST(SocketBrokerImplTest, TestCanOpenSocket) {
+  SocketBrokerImpl socket_broker_impl;
+  base::test::TaskEnvironment task_environment;
+  base::RunLoop run_loop;
+  mojo::Remote<network::mojom::SocketBroker> remote(
+      socket_broker_impl.BindNewRemote());
+  remote->CreateTcpSocket(net::ADDRESS_FAMILY_IPV4,
+                          base::BindOnce(&DidCompleteCreateTest, &run_loop));
+  run_loop.Run();
+
+  base::RunLoop run_loop2;
+  remote->CreateTcpSocket(net::ADDRESS_FAMILY_IPV6,
+                          base::BindOnce(&DidCompleteCreateTest, &run_loop2));
+  run_loop2.Run();
+}
+
+}  // namespace content
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index e9b0b11..d254425 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -142,6 +142,12 @@
       network::mojom::ConnectionSubtype(
           net::NetworkChangeNotifier::GetConnectionSubtype()));
 }
+
+mojo::PendingRemote<network::mojom::SocketBroker>
+NetworkServiceClient::BindSocketBroker() {
+  return socket_broker_.BindNewRemote();
+}
+
 #endif
 
 mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
diff --git a/content/browser/network_service_client.h b/content/browser/network_service_client.h
index 734b968..18ce6598 100644
--- a/content/browser/network_service_client.h
+++ b/content/browser/network_service_client.h
@@ -12,6 +12,7 @@
 #include "base/memory/memory_pressure_listener.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
+#include "content/browser/net/socket_broker_impl.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
@@ -80,6 +81,9 @@
 
   // net::NetworkChangeNotifier::DNSObserver implementation:
   void OnDNSChanged() override;
+
+  // Called when the network service sandbox is enabled.
+  mojo::PendingRemote<network::mojom::SocketBroker> BindSocketBroker();
 #endif
 
  private:
@@ -126,6 +130,7 @@
   std::unique_ptr<base::android::ApplicationStatusListener>
       app_status_listener_;
   mojo::Remote<network::mojom::NetworkChangeManager> network_change_manager_;
+  SocketBrokerImpl socket_broker_;
 #endif
 
   mojo::ReceiverSet<network::mojom::URLLoaderNetworkServiceObserver>
diff --git a/content/browser/network_service_instance_impl.cc b/content/browser/network_service_instance_impl.cc
index 2308cd96..0ab1ee90 100644
--- a/content/browser/network_service_instance_impl.cc
+++ b/content/browser/network_service_instance_impl.cc
@@ -34,6 +34,7 @@
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/first_party_sets/first_party_sets_handler_impl.h"
 #include "content/browser/net/http_cache_backend_file_operations_factory.h"
+#include "content/browser/net/socket_broker_impl.h"
 #include "content/browser/network_sandbox_grant_result.h"
 #include "content/browser/network_service_client.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -49,6 +50,7 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "net/base/features.h"
 #include "net/log/net_log_util.h"
+#include "sandbox/policy/features.h"
 #include "services/cert_verifier/cert_verifier_service_factory.h"
 #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
 #include "services/network/network_service.h"
@@ -59,6 +61,7 @@
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/network_service_test.mojom.h"
+#include "services/network/public/mojom/socket_broker.mojom.h"
 
 #if !BUILDFLAG(IS_ANDROID)
 #include "content/browser/network_sandbox.h"
@@ -832,6 +835,11 @@
   }
 
 #if BUILDFLAG(IS_ANDROID)
+
+  if (sandbox::policy::features::IsNetworkSandboxEnabled() &&
+      !params->socket_broker) {
+    params->socket_broker = g_client->BindSocketBroker();
+  }
   // On Android, if a cookie_manager pending receiver was passed then migration
   // should not be attempted as the cookie file is already being accessed by the
   // browser instance.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 6a94b868..4546a4e3 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -217,6 +217,8 @@
 #include "components/services/font/public/mojom/font_service.mojom.h"  // nogncheck
 #include "content/browser/font_service.h"  // nogncheck
 #include "third_party/blink/public/mojom/memory_usage_monitor_linux.mojom.h"  // nogncheck
+
+#include "content/public/browser/stable_video_decoder_factory.h"
 #endif
 
 #if BUILDFLAG(IS_MAC)
@@ -2094,6 +2096,23 @@
       std::move(receiver));
 }
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+void RenderProcessHostImpl::CreateStableVideoDecoder(
+    mojo::PendingReceiver<media::stable::mojom::StableVideoDecoder> receiver) {
+  if (!stable_video_decoder_factory_remote_.is_bound()) {
+    LaunchStableVideoDecoderFactory(
+        stable_video_decoder_factory_remote_.BindNewPipeAndPassReceiver());
+    stable_video_decoder_factory_remote_.reset_on_disconnect();
+  }
+
+  if (!stable_video_decoder_factory_remote_.is_bound())
+    return;
+
+  stable_video_decoder_factory_remote_->CreateStableVideoDecoder(
+      std::move(receiver));
+}
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 void RenderProcessHostImpl::DelayProcessShutdown(
     const base::TimeDelta& subframe_shutdown_timeout,
     const base::TimeDelta& unload_handler_timeout,
@@ -2439,7 +2458,8 @@
 void RenderProcessHostImpl::BindMediaInterfaceProxy(
     mojo::PendingReceiver<media::mojom::InterfaceFactory> receiver) {
   if (!media_interface_proxy_)
-    media_interface_proxy_ = std::make_unique<FramelessMediaInterfaceProxy>();
+    media_interface_proxy_ =
+        std::make_unique<FramelessMediaInterfaceProxy>(this);
   media_interface_proxy_->Add(std::move(receiver));
 }
 
@@ -4684,6 +4704,10 @@
   coordinator_connector_receiver_.reset();
   tracing_registration_.reset();
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  stable_video_decoder_factory_remote_.reset();
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
   // Destroy all embedded CompositorFrameSinks.
   embedded_frame_sink_provider_.reset();
 
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 34e67e8..f5e6061b 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -83,6 +83,10 @@
 #include "content/public/browser/android/child_process_importance.h"
 #endif
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "media/mojo/mojom/stable/stable_video_decoder.mojom.h"
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 namespace base {
 class CommandLine;
 class PersistentMemoryAllocator;
@@ -669,6 +673,12 @@
       mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver)
       override;
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  void CreateStableVideoDecoder(
+      mojo::PendingReceiver<media::stable::mojom::StableVideoDecoder> receiver)
+      override;
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
   void BindP2PSocketManager(
       net::NetworkIsolationKey isolation_key,
       mojo::PendingReceiver<network::mojom::P2PSocketManager> receiver,
@@ -1113,6 +1123,13 @@
   // RenderProcessHost. This is destroyed early in ResetIPC() method.
   std::unique_ptr<PermissionServiceContext> permission_service_context_;
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  // Connection to the StableVideoDecoderFactory that lives in a utility
+  // process. This is only used for out-of-process video decoding.
+  mojo::Remote<media::stable::mojom::StableVideoDecoderFactory>
+      stable_video_decoder_factory_remote_;
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
   // The memory allocator, if any, in which the renderer will write its metrics.
   std::unique_ptr<base::PersistentMemoryAllocator> metrics_allocator_;
 
diff --git a/content/browser/resources/quota/BUILD.gn b/content/browser/resources/quota/BUILD.gn
index e0dec73..b77a86f 100644
--- a/content/browser/resources/quota/BUILD.gn
+++ b/content/browser/resources/quota/BUILD.gn
@@ -7,19 +7,6 @@
 import("//tools/typescript/ts_library.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
-generate_grd("build_grd") {
-  grd_prefix = "quota_internals"
-  out_grd = "$target_gen_dir/resources.grd"
-  input_files = [
-    "quota_internals.html",
-    "quota_internals.css",
-  ]
-  input_files_base_dir = rebase_path(".", "//")
-
-  deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 copy("copy_ts") {
   sources = [
     "quota_internals.ts",
@@ -70,3 +57,17 @@
     ":copy_ts",
   ]
 }
+
+generate_grd("build_grd") {
+  grd_prefix = "quota_internals"
+  out_grd = "$target_gen_dir/resources.grd"
+  input_files = [
+    "quota_internals.html",
+    "quota_internals.css",
+  ]
+  input_files_base_dir = rebase_path(".", "//")
+
+  deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+}
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 7d39cec..a0545b14 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -53,6 +53,10 @@
 #include "content/public/browser/android/child_process_importance.h"
 #endif
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "media/mojo/mojom/stable/stable_video_decoder.mojom-forward.h"
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
 class GURL;
 
 namespace base {
@@ -621,6 +625,12 @@
       const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver) = 0;
 
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  virtual void CreateStableVideoDecoder(
+      mojo::PendingReceiver<media::stable::mojom::StableVideoDecoder>
+          receiver) = 0;
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+
   // Returns the current number of active views in this process.  Excludes
   // any RenderViewHosts that are swapped out.
   size_t GetActiveViewCount();
diff --git a/content/public/browser/stable_video_decoder_factory.h b/content/public/browser/stable_video_decoder_factory.h
index c9939c6..e3178c3f 100644
--- a/content/public/browser/stable_video_decoder_factory.h
+++ b/content/public/browser/stable_video_decoder_factory.h
@@ -7,13 +7,15 @@
 
 #include "content/common/content_export.h"
 #include "media/mojo/mojom/stable/stable_video_decoder.mojom-forward.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace content {
 
-// Returns the browser's remote interface to the global
-// StableVideoDecoderFactory which runs out-of-process.
-CONTENT_EXPORT media::stable::mojom::StableVideoDecoderFactory&
-GetStableVideoDecoderFactory();
+// Binds a StableVideoDecoderFactory PendingReceiver by either using the
+// crosapi (on LaCrOS) or starting a new utility process (on non-LaCrOS).
+CONTENT_EXPORT void LaunchStableVideoDecoderFactory(
+    mojo::PendingReceiver<media::stable::mojom::StableVideoDecoderFactory>
+        receiver);
 
 }  // namespace content
 
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index c640e80..fb779e61 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -257,6 +257,11 @@
       const blink::StorageKey& storage_key,
       mojo::PendingReceiver<blink::mojom::WebSocketConnector> receiver)
       override {}
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+  void CreateStableVideoDecoder(
+      mojo::PendingReceiver<media::stable::mojom::StableVideoDecoder> receiver)
+      override {}
+#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
 
   std::string GetInfoForBrowserContextDestructionCrashReporting() override;
   void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const override;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index b6d6b3c..0355b67 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1315,6 +1315,7 @@
     "../browser/net/network_field_trial_browsertest.cc",
     "../browser/net/sandboxed_http_cache_browsertest.cc",
     "../browser/net/sandboxed_nqe_browsertest.cc",
+    "../browser/net/sandboxed_socket_broker_browsertest.cc",
     "../browser/net/split_cache_browsertest.cc",
     "../browser/net/trust_token_browsertest.cc",
     "../browser/net/trust_token_browsertest.h",
@@ -2251,6 +2252,7 @@
     "../browser/net/cross_origin_embedder_policy_reporter_unittest.cc",
     "../browser/net/cross_origin_opener_policy_reporter_unittest.cc",
     "../browser/net/network_quality_observer_impl_unittest.cc",
+    "../browser/net/socket_broker_impl_unittest.cc",
     "../browser/network_context_client_base_impl_unittest.cc",
     "../browser/notification_service_impl_unittest.cc",
     "../browser/notifications/blink_notification_service_impl_unittest.cc",
diff --git a/docs/webui_build_configuration.md b/docs/webui_build_configuration.md
index ed9080ef..5ab79cbf 100644
--- a/docs/webui_build_configuration.md
+++ b/docs/webui_build_configuration.md
@@ -134,7 +134,7 @@
 This rule is used to compile TypeScript code to JavaScript. It outputs JS files
 corresponding to each TS file passed as an input into the designated output
 directory, and generates a manifest listing all the files it has output named
-tsconfig.manifest in the target generated directory.
+$target_name.manifest in the target generated directory.
 ```
 
 #### **Input File notes**
@@ -179,7 +179,7 @@
                absolute 'chrome://resources/' paths are already mapped by
                default.
 manifest_excludes: List of input files to exclude from the output
-                   tsconfig.manifest.
+                   the manifest file.
 ```
 
 #### **Example**
@@ -310,7 +310,9 @@
   input_files = [ "my_webui.html" ]
   input_files_base_dir = rebase_path(".", "//")
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files = filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  # Or, configure statically the manifest file name:
+  # manifest_files = [ "$target_gen_dir/build_ts.manifest" ]
   grd_prefix = "my_webui"
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
 }
@@ -392,7 +394,7 @@
 }
 
 # Both the HTML file and the JS file created by ts_library need to be listed in
-# the grd. The JS file is already listed in the tsconfig.manifest generated by
+# the grd. The JS file is already listed in the build_ts.manifest generated by
 # ts_library(). Pass the HTML file via |input_files|.
 generate_grd("build_grd") {
   deps = [ ":build_ts" ]
@@ -400,7 +402,7 @@
   out_grd = "$target_gen_dir/resources.grd"
   input_files = [ "my_debug_page_index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files = filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
 
 # Create the pak, header, and resource map files.
@@ -475,7 +477,7 @@
 }
 
 # The HTML file and the JS files created by ts_library need to be listed in
-# the grd. The JS files are already listed in the tsconfig.manifest generated by
+# the grd. The JS files are already listed in the build_ts.manifest generated by
 # ts_library(). Pass the HTML file via |input_files|.
 generate_grd("build_grd") {
   deps = [ ":build_ts" ]
@@ -483,7 +485,7 @@
   out_grd = "$target_gen_dir/resources.grd"
   input_files = [ "my_debug_page_index.html" ]
   input_files_base_dir = rebase_path(".", "//")
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files = filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
 }
 
 # Create the pak, header, and resource map files.
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index b64fb8a0..4677d4a 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1738,6 +1738,7 @@
   DEVELOPERPRIVATE_GETUSERANDEXTENSIONSITESBYETLD = 1675,
   AUTOTESTPRIVATE_SENDARCOVERLAYCOLOR = 1676,
   AUTOTESTPRIVATE_ISINPUTMETHODREADYFORTESTING = 1677,
+  AUTOTESTPRIVATE_GETARCAPPKILLS = 1678,
   // Last entry: Add new entries above, then run:
   // tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/google_apis/google_api_keys_unittest.cc b/google_apis/google_api_keys_unittest.cc
index 1861bfb..08aeeef 100644
--- a/google_apis/google_api_keys_unittest.cc
+++ b/google_apis/google_api_keys_unittest.cc
@@ -21,14 +21,12 @@
 #include "google_apis/gaia/gaia_switches.h"
 #include "google_apis/google_api_keys.h"
 
-// The Win builders fail (with a linker crash) when trying to link
-// unit_tests, and the Android builders complain about multiply
-// defined symbols (likely they don't do name decoration as well as
-// the Mac and Linux linkers).  Therefore these tests are only built
-// and run on Mac, Linux and Fuchsia, which should provide plenty of coverage
-// since there are no platform-specific bits in this code.
-#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE) || \
-    BUILDFLAG(IS_FUCHSIA)
+// The Win builders fail (with a linker crash) when trying to link unit_tests,
+// and the Android builders complain about multiply defined symbols (likely they
+// don't do name decoration as well as the Mac and Linux linkers). Building and
+// running on other platforms should provide plenty of coverage since there are
+// no platform-specific bits in this code.
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN)
 
 // We need to include everything included by google_api_keys.cc once
 // at global scope so that things like STL and classes from base don't
@@ -586,5 +584,4 @@
   GaiaConfig::ResetInstanceForTesting();
 }
 
-#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
-        // || BUILDFLAG(IS_FUCHSIA)
+#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN)
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 781467c..1184bc65 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -17,6 +17,7 @@
 #include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "base/values.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
@@ -85,21 +86,21 @@
 
   void AppendAsTraceFormat(std::string* out) const override {
     std::string tmp;
-    base::JSONWriter::Write(*value_, &tmp);
+    base::JSONWriter::Write(value_, &tmp);
     *out += tmp;
   }
 
  private:
-  explicit DevToolsChannelData(base::Value* value) : value_(value) {}
-  std::unique_ptr<base::Value> value_;
+  explicit DevToolsChannelData(base::Value value) : value_(std::move(value)) {}
+  base::Value value_;
 };
 
 std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
 DevToolsChannelData::CreateForChannel(GpuChannel* channel) {
-  std::unique_ptr<base::DictionaryValue> res(new base::DictionaryValue);
-  res->SetInteger("renderer_pid", channel->client_pid());
-  res->SetDouble("used_bytes", channel->GetMemoryUsage());
-  return base::WrapUnique(new DevToolsChannelData(res.release()));
+  base::Value::Dict res;
+  res.Set("renderer_pid", static_cast<int>(channel->client_pid()));
+  res.Set("used_bytes", static_cast<double>(channel->GetMemoryUsage()));
+  return base::WrapUnique(new DevToolsChannelData(base::Value(std::move(res))));
 }
 
 }  // namespace
diff --git a/infra/config/chops-weetbix-dev.cfg b/infra/config/chops-weetbix-dev.cfg
index 2ce5db0..84f0952 100644
--- a/infra/config/chops-weetbix-dev.cfg
+++ b/infra/config/chops-weetbix-dev.cfg
@@ -68,11 +68,9 @@
     threshold {
       # Clusters which fail to meet this threshold will be closed.
       presubmit_runs_failed {
-        one_day: 1
         seven_day: 1
       }
       critical_failures_exonerated {
-        three_day: 1
         seven_day: 1
       }
     }
diff --git a/infra/config/chops-weetbix.cfg b/infra/config/chops-weetbix.cfg
index 8e09fd8c9..d8c1eda 100644
--- a/infra/config/chops-weetbix.cfg
+++ b/infra/config/chops-weetbix.cfg
@@ -68,11 +68,9 @@
     threshold {
       # Clusters which fail to meet this threshold will be closed.
       presubmit_runs_failed {
-        one_day: 1
         seven_day: 1
       }
       critical_failures_exonerated {
-        three_day: 1
         seven_day: 1
       }
     }
diff --git a/infra/config/generated/luci/chops-weetbix-dev.cfg b/infra/config/generated/luci/chops-weetbix-dev.cfg
index 2ce5db0..84f0952 100644
--- a/infra/config/generated/luci/chops-weetbix-dev.cfg
+++ b/infra/config/generated/luci/chops-weetbix-dev.cfg
@@ -68,11 +68,9 @@
     threshold {
       # Clusters which fail to meet this threshold will be closed.
       presubmit_runs_failed {
-        one_day: 1
         seven_day: 1
       }
       critical_failures_exonerated {
-        three_day: 1
         seven_day: 1
       }
     }
diff --git a/infra/config/generated/luci/chops-weetbix.cfg b/infra/config/generated/luci/chops-weetbix.cfg
index 8e09fd8c9..d8c1eda 100644
--- a/infra/config/generated/luci/chops-weetbix.cfg
+++ b/infra/config/generated/luci/chops-weetbix.cfg
@@ -68,11 +68,9 @@
     threshold {
       # Clusters which fail to meet this threshold will be closed.
       presubmit_runs_failed {
-        one_day: 1
         seven_day: 1
       }
       critical_failures_exonerated {
-        three_day: 1
         seven_day: 1
       }
     }
diff --git a/infra/config/generated/luci/project.cfg b/infra/config/generated/luci/project.cfg
index 174d8ab..bddd90a 100644
--- a/infra/config/generated/luci/project.cfg
+++ b/infra/config/generated/luci/project.cfg
@@ -7,7 +7,7 @@
 name: "chromium"
 access: "group:all"
 lucicfg {
-  version: "1.31.3"
+  version: "1.31.4"
   package_dir: "../.."
   config_dir: "generated/luci"
   entry_point: "main.star"
diff --git a/ios/PRESUBMIT.py b/ios/PRESUBMIT.py
index 6c76d51..14eb546 100644
--- a/ios/PRESUBMIT.py
+++ b/ios/PRESUBMIT.py
@@ -15,6 +15,8 @@
 NULLABILITY_PATTERN = r'(nonnull|nullable|_Nullable|_Nonnull)'
 TODO_PATTERN = r'TO[D]O\(([^\)]*)\)'
 CRBUG_PATTERN = r'crbug\.com/\d+$'
+INCLUDE_PATTERN = r'^#include'
+IOS_PACKAGE_PATTERN = r'^ios'
 ARC_COMPILE_GUARD = [
     '#if !defined(__has_feature) || !__has_feature(objc_arc)',
     '#error "This file requires ARC support."',
@@ -95,6 +97,48 @@
   return [output_api.PresubmitError(error_message)]
 
 
+def _CheckHasNoIncludeDirectives(input_api, output_api):
+  """ Checks that #include preprocessor directives are not present."""
+  errors = []
+  for f in input_api.AffectedFiles():
+    if not _IsInIosPackage(input_api, f.LocalPath()):
+      continue
+    _, ext = os.path.splitext(f.LocalPath())
+    if ext != '.mm':
+      continue
+    for line_num, line in f.ChangedContents():
+      if _HasIncludeDirective(input_api, line):
+        errors.append('%s:%s' % (f.LocalPath(), line_num))
+  if not errors:
+    return []
+
+  singular_plural = 'it' if len(errors) == 1 else 'them'
+  plural_suffix = '' if len(errors) == 1 else 's'
+  error_message = '\n'.join([
+      'Found usage of `#include` preprocessor directive%(plural)s! Please, '
+      'replace %(singular_plural)s with `#import` preprocessor '
+      'directive%(plural)s instead. '
+      'Consider replacing all existing `#include` with `#import` (if any) in '
+      'this file for the code clean up. See //styleguide/objective-c/'
+      'objective-c.md#import-and-include-in-the-directory for more details. '
+      '\n\nAffected file%(plural)s:' % {'plural': plural_suffix,
+      'singular_plural': singular_plural }
+  ] + errors) + '\n'
+
+  return [output_api.PresubmitError(error_message)]
+
+def _IsInIosPackage(input_api, path):
+  """ Returns True if path is within ios package"""
+  ios_package_regex = input_api.re.compile(IOS_PACKAGE_PATTERN)
+
+  return ios_package_regex.search(path)
+
+def _HasIncludeDirective(input_api, line):
+  """ Returns True if #include is found in the line"""
+  include_regex = input_api.re.compile(INCLUDE_PATTERN)
+
+  return include_regex.search(line)
+
 def _HasToDoWithNoBug(input_api, line):
   """ Returns True if TODO is not identified by a bug number."""
   todo_regex = input_api.re.compile(TODO_PATTERN)
@@ -112,4 +156,5 @@
   results.extend(_CheckBugInToDo(input_api, output_api))
   results.extend(_CheckNullabilityAnnotations(input_api, output_api))
   results.extend(_CheckARCCompilationGuard(input_api, output_api))
+  results.extend(_CheckHasNoIncludeDirectives(input_api, output_api))
   return results
diff --git a/ios/PRESUBMIT_test.py b/ios/PRESUBMIT_test.py
index bc5acaf1..69a30ead 100755
--- a/ios/PRESUBMIT_test.py
+++ b/ios/PRESUBMIT_test.py
@@ -80,5 +80,36 @@
     self.assertEqual(len(error_lines), len(bad_lines) + 2)
 
 
+class CheckHasNoIncludeDirectivesTest(unittest.TestCase):
+  """Test the _CheckHasNoIncludeDirectives presubmit check."""
+
+  def testFindsIncludeDirectives(self):
+    good_lines = ['#import <system>',
+                  '#import "my/path/my/header.h"',
+                  '#import "my/path/my/source.mm"',
+                  '#import "my/path/my/source.m"']
+    bad_lines = ['#include <system>',
+                 '#import <system>',
+                 '#include "my/path/my/header.h"',
+                 '#include "my/path/my/source.mm"',
+                 '#import "my/path/my/header.h"'
+                 '#include "my/path/my/source.m"']
+    mock_input = PRESUBMIT_test_mocks.MockInputApi()
+    mock_input.files = [
+      PRESUBMIT_test_mocks.MockFile('ios/path/foo_controller.mm', bad_lines),
+      PRESUBMIT_test_mocks.MockFile('ios/path/foo_controller_2.mm', good_lines),
+      PRESUBMIT_test_mocks.MockFile('ios/path/bar_controller.h', bad_lines),
+      PRESUBMIT_test_mocks.MockFile('ios/path/bar_controller.m', bad_lines),
+      PRESUBMIT_test_mocks.MockFile('ios/path/bar_controller.cc', bad_lines),
+      PRESUBMIT_test_mocks.MockFile('chrome/path/foo_controller.mm', bad_lines),
+    ]
+    mock_output = PRESUBMIT_test_mocks.MockOutputApi()
+    errors = PRESUBMIT._CheckHasNoIncludeDirectives(mock_input, mock_output)
+    self.assertEqual(len(errors), 1)
+    self.assertEqual('error', errors[0].type)
+    self.assertTrue('ios/path/foo_controller.mm:1' in errors[0].message)
+    self.assertTrue('ios/path/foo_controller.mm:3' in errors[0].message)
+    self.assertTrue('ios/path/foo_controller.mm:4' in errors[0].message)
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
index 9e51186b..34a8e18 100644
--- a/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
+++ b/ios/chrome/browser/autofill/manual_fill/passwords_fetcher_unittest.mm
@@ -115,12 +115,6 @@
   void AddBlockedForm() {
     auto form = std::make_unique<password_manager::PasswordForm>();
     form->url = GURL("http://www.secret.com/login");
-    form->action = GURL("http://www.secret.com/action");
-    form->username_element = u"email";
-    form->username_value = u"test@secret.com";
-    form->password_element = u"password";
-    form->password_value = u"cantsay";
-    form->submit_element = u"signIn";
     form->signon_realm = "http://www.secret.test/";
     form->scheme = password_manager::PasswordForm::Scheme::kHtml;
     form->blocked_by_user = true;
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.h b/ios/chrome/browser/browser_state/chrome_browser_state.h
index 50db764..4e3d201 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state.h
@@ -91,17 +91,17 @@
   virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() = 0;
 
   // Retrieves a pointer to the PrefService that manages the preferences.
-  virtual PrefService* GetPrefs() = 0;
+  virtual PrefService* GetPrefs();
+
+  // Retrieves a pointer to the PrefService that manages the preferences as
+  // a sync_preferences::PrefServiceSyncable.
+  virtual sync_preferences::PrefServiceSyncable* GetSyncablePrefs() = 0;
 
   // Allows access to ChromeBrowserStateIOData without going through
   // ResourceContext that is not compiled on iOS. This method must be called on
   // UI thread, but the returned object must only be accessed on the IO thread.
   virtual ChromeBrowserStateIOData* GetIOData() = 0;
 
-  // Retrieves a pointer to the PrefService that manages the preferences as
-  // a sync_preferences::PrefServiceSyncable.
-  virtual sync_preferences::PrefServiceSyncable* GetSyncablePrefs();
-
   // Deletes all network related data since `time`. It deletes transport
   // security state since `time` and it also deletes HttpServerProperties data.
   // Works asynchronously, however if the `completion` callback is non-null, it
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state.mm b/ios/chrome/browser/browser_state/chrome_browser_state.mm
index 9af674eb..fb19efe 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state.mm
@@ -75,8 +75,8 @@
   return io_task_runner_;
 }
 
-sync_preferences::PrefServiceSyncable* ChromeBrowserState::GetSyncablePrefs() {
-  return static_cast<sync_preferences::PrefServiceSyncable*>(GetPrefs());
+PrefService* ChromeBrowserState::GetPrefs() {
+  return GetSyncablePrefs();
 }
 
 net::URLRequestContextGetter* ChromeBrowserState::GetRequestContext() {
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
index f04ce7b9..35114c04 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.h
@@ -42,7 +42,7 @@
   PrefProxyConfigTracker* GetProxyConfigTracker() override;
   BrowserStatePolicyConnector* GetPolicyConnector() override;
   policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
-  PrefService* GetPrefs() override;
+  sync_preferences::PrefServiceSyncable* GetSyncablePrefs() override;
   ChromeBrowserStateIOData* GetIOData() override;
   void ClearNetworkingHistorySince(base::Time time,
                                    base::OnceClosure completion) override;
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm b/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm
index 4b346e18..004cea36 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_impl.mm
@@ -208,7 +208,8 @@
   return user_cloud_policy_manager_.get();
 }
 
-PrefService* ChromeBrowserStateImpl::GetPrefs() {
+sync_preferences::PrefServiceSyncable*
+ChromeBrowserStateImpl::GetSyncablePrefs() {
   DCHECK(prefs_);  // Should explicitly be initialized.
   return prefs_.get();
 }
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
index d456cd5e..fb64f5c 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.h
@@ -37,7 +37,7 @@
   PrefProxyConfigTracker* GetProxyConfigTracker() override;
   BrowserStatePolicyConnector* GetPolicyConnector() override;
   policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
-  PrefService* GetPrefs() override;
+  sync_preferences::PrefServiceSyncable* GetSyncablePrefs() override;
   ChromeBrowserStateIOData* GetIOData() override;
   void ClearNetworkingHistorySince(base::Time time,
                                    base::OnceClosure completion) override;
diff --git a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm
index 3bef75d..ab3b83e 100644
--- a/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm
+++ b/ios/chrome/browser/browser_state/off_the_record_chrome_browser_state_impl.mm
@@ -92,7 +92,8 @@
   return GetOriginalChromeBrowserState()->GetUserCloudPolicyManager();
 }
 
-PrefService* OffTheRecordChromeBrowserStateImpl::GetPrefs() {
+sync_preferences::PrefServiceSyncable*
+OffTheRecordChromeBrowserStateImpl::GetSyncablePrefs() {
   return prefs_.get();
 }
 
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.h b/ios/chrome/browser/browser_state/test_chrome_browser_state.h
index fa8f57a..c89ab1ce 100644
--- a/ios/chrome/browser/browser_state/test_chrome_browser_state.h
+++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.h
@@ -56,7 +56,7 @@
   ChromeBrowserState* GetOffTheRecordChromeBrowserState() override;
   PrefProxyConfigTracker* GetProxyConfigTracker() override;
   BrowserStatePolicyConnector* GetPolicyConnector() override;
-  PrefService* GetPrefs() override;
+  sync_preferences::PrefServiceSyncable* GetSyncablePrefs() override;
   ChromeBrowserStateIOData* GetIOData() override;
   void ClearNetworkingHistorySince(base::Time time,
                                    base::OnceClosure completion) override;
diff --git a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
index 29e14a79..7c278a1 100644
--- a/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
+++ b/ios/chrome/browser/browser_state/test_chrome_browser_state.mm
@@ -231,7 +231,8 @@
   return policy_connector_.get();
 }
 
-PrefService* TestChromeBrowserState::GetPrefs() {
+sync_preferences::PrefServiceSyncable*
+TestChromeBrowserState::GetSyncablePrefs() {
   return prefs_.get();
 }
 
diff --git a/ios/chrome/browser/flags/BUILD.gn b/ios/chrome/browser/flags/BUILD.gn
index 38617da..4cbd99f 100644
--- a/ios/chrome/browser/flags/BUILD.gn
+++ b/ios/chrome/browser/flags/BUILD.gn
@@ -58,6 +58,7 @@
     "//ios/chrome/browser/screen_time:buildflags",
     "//ios/chrome/browser/sessions:features",
     "//ios/chrome/browser/ui:feature_flags",
+    "//ios/chrome/browser/ui/autofill:features",
     "//ios/chrome/browser/ui/bubble:features",
     "//ios/chrome/browser/ui/content_suggestions:feature_flags",
     "//ios/chrome/browser/ui/default_promo:utils",
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 3f34bc83..b604a37 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -69,6 +69,7 @@
 #include "ios/chrome/browser/screen_time/screen_time_buildflags.h"
 #import "ios/chrome/browser/sessions/session_features.h"
 #include "ios/chrome/browser/system_flags.h"
+#include "ios/chrome/browser/ui/autofill/features.h"
 #include "ios/chrome/browser/ui/bubble/bubble_features.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_feature.h"
 #import "ios/chrome/browser/ui/default_promo/default_browser_utils.h"
@@ -982,6 +983,11 @@
      flag_descriptions::kAutofillParseIbanFieldsName,
      flag_descriptions::kAutofillParseIbanFieldsDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillParseIbanFields)},
+    {"autofill-enable-new-card-unmask-prompt-view",
+     flag_descriptions::kAutofillEnableNewCardUnmaskPromptViewName,
+     flag_descriptions::kAutofillEnableNewCardUnmaskPromptViewDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kAutofillEnableNewCardUnmaskPromptView)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 48f9f815..799de49 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -22,6 +22,12 @@
     "Offers uploading Autofilled credit cards to Google Payments after form "
     "submission.";
 
+const char kAutofillEnableNewCardUnmaskPromptViewName[] =
+    "Enable the new Card Unmask Prompt View for Autofill.";
+const char kAutofillEnableNewCardUnmaskPromptViewDescription[] =
+    "Displays the new autofill prompt for entering a credit card's CVC and "
+    "(optional) expiration date.";
+
 const char kAutofillEnableRankingFormulaName[] =
     "Enable new Autofill suggestion ranking formula";
 const char kAutofillEnableRankingFormulaDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index 9bd2564..befe2d07 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -20,6 +20,11 @@
 extern const char kAutofillCreditCardUploadName[];
 extern const char kAutofillCreditCardUploadDescription[];
 
+// Title and description for the flag to enable the new Card Unmask Prompt View
+// in Autofill.
+extern const char kAutofillEnableNewCardUnmaskPromptViewName[];
+extern const char kAutofillEnableNewCardUnmaskPromptViewDescription[];
+
 // Title and description for the flag to control the new autofill suggestion
 // ranking formula.
 extern const char kAutofillEnableRankingFormulaName[];
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn
index 4b042da..238a7d1 100644
--- a/ios/chrome/browser/ui/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -237,3 +237,12 @@
     "//ios/third_party/earl_grey2:test_lib",
   ]
 }
+
+source_set("features") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "features.cc",
+    "features.h",
+  ]
+  public_deps = [ "//base" ]
+}
diff --git a/ios/chrome/browser/ui/autofill/features.cc b/ios/chrome/browser/ui/autofill/features.cc
new file mode 100644
index 0000000..82ad417
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/features.cc
@@ -0,0 +1,8 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/ui/autofill/features.h"
+
+const base::Feature kAutofillEnableNewCardUnmaskPromptView{
+    "AutofillEnableNewCardUnmaskPromptView", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/autofill/features.h b/ios/chrome/browser/ui/autofill/features.h
new file mode 100644
index 0000000..2ac1e38
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/features.h
@@ -0,0 +1,13 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_AUTOFILL_FEATURES_H_
+#define IOS_CHROME_BROWSER_UI_AUTOFILL_FEATURES_H_
+
+#include "base/feature_list.h"
+
+// Feature flag to enable using the new Card Unmask Prompt View in Autofill.
+extern const base::Feature kAutofillEnableNewCardUnmaskPromptView;
+
+#endif  // IOS_CHROME_BROWSER_UI_AUTOFILL_FEATURES_H_
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index aa0847a9..ce0ee79 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -161,11 +161,11 @@
   self.suppressTableViewUpdates = YES;
   [self loadModel];
   self.suppressTableViewUpdates = NO;
+  [self.dataManager prepare];
 }
 
 - (void)viewWillAppear:(BOOL)animated {
   [super viewWillAppear:animated];
-  [self.dataManager prepare];
   [self.dataManager restartCounters:BrowsingDataRemoveMask::REMOVE_ALL];
 
   [self updateToolbarButtons];
@@ -174,11 +174,6 @@
   self.navigationController.toolbarHidden = NO;
 }
 
-- (void)viewWillDisappear:(BOOL)animated {
-  [super viewWillDisappear:animated];
-  [self.dataManager disconnect];
-}
-
 - (void)loadModel {
   [super loadModel];
   [self.dataManager loadModel:self.tableViewModel];
@@ -206,6 +201,7 @@
     self.navigationController.interactivePopGestureRecognizer.delegate = nil;
     self.overlayCoordinator = nil;
   }
+  [self.dataManager disconnect];
 }
 
 #pragma mark - UIGestureRecognizerDelegate
diff --git a/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm
index 3674d92..539c587 100644
--- a/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/password/password_manager_view_controller_unittest.mm
@@ -242,12 +242,6 @@
   void AddBlockedForm1() {
     auto form = std::make_unique<password_manager::PasswordForm>();
     form->url = GURL("http://www.secret.com/login");
-    form->action = GURL("http://www.secret.com/action");
-    form->username_element = u"email";
-    form->username_value = u"test@secret.com";
-    form->password_element = u"password";
-    form->password_value = u"cantsay";
-    form->submit_element = u"signIn";
     form->signon_realm = "http://www.secret.com/";
     form->scheme = password_manager::PasswordForm::Scheme::kHtml;
     form->blocked_by_user = true;
@@ -259,12 +253,6 @@
   void AddBlockedForm2() {
     auto form = std::make_unique<password_manager::PasswordForm>();
     form->url = GURL("http://www.secret2.com/login");
-    form->action = GURL("http://www.secret2.com/action");
-    form->username_element = u"email";
-    form->username_value = u"test@secret2.com";
-    form->password_element = u"password";
-    form->password_value = u"cantsay";
-    form->submit_element = u"signIn";
     form->signon_realm = "http://www.secret2.com/";
     form->scheme = password_manager::PasswordForm::Scheme::kHtml;
     form->blocked_by_user = true;
diff --git a/ios/web/public/js_messaging/compile_ts.gni b/ios/web/public/js_messaging/compile_ts.gni
index 9de8231..3debc5f 100644
--- a/ios/web/public/js_messaging/compile_ts.gni
+++ b/ios/web/public/js_messaging/compile_ts.gni
@@ -49,7 +49,8 @@
   }
 
   # Compile the scripts and output them into `compiled_scripts_dir` in the same
-  # directory structure to maintain path imports specified in tsconfig.manifest
+  # directory structure to maintain path imports specified in the tsc manifest
+  # file.
   ts_library(target_name) {
     forward_variables_from(invoker, [ "deps" ])
 
diff --git a/ios/web/public/js_messaging/optimize_js.gni b/ios/web/public/js_messaging/optimize_js.gni
index cf23eb0..ec3aaff 100644
--- a/ios/web/public/js_messaging/optimize_js.gni
+++ b/ios/web/public/js_messaging/optimize_js.gni
@@ -90,7 +90,8 @@
       foreach(_dep, invoker.deps) {
         _dep_gen_dir =
             rebase_path(get_label_info(_dep, "target_gen_dir"), root_build_dir)
-        args += [ "$_dep_gen_dir/tsconfig.manifest" ]
+        name = get_label_info(_dep, "name")
+        args += [ "$_dep_gen_dir/$name.manifest" ]
       }
     }
   }
diff --git a/media/capture/video/chromeos/camera_device_delegate_unittest.cc b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
index b983758..42ede88 100644
--- a/media/capture/video/chromeos/camera_device_delegate_unittest.cc
+++ b/media/capture/video/chromeos/camera_device_delegate_unittest.cc
@@ -136,8 +136,7 @@
  public:
   CameraDeviceDelegateTest()
       : mock_camera_device_receiver_(&mock_camera_device_),
-        device_delegate_thread_("DeviceDelegateThread"),
-        hal_delegate_thread_("HalDelegateThread") {}
+        device_delegate_thread_("DeviceDelegateThread") {}
 
   CameraDeviceDelegateTest(const CameraDeviceDelegateTest&) = delete;
   CameraDeviceDelegateTest& operator=(const CameraDeviceDelegateTest&) = delete;
@@ -145,9 +144,12 @@
   void SetUp() override {
     VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager(
         &mock_gpu_memory_buffer_manager_);
-    hal_delegate_thread_.Start();
-    camera_hal_delegate_ =
-        std::make_unique<CameraHalDelegate>(hal_delegate_thread_.task_runner());
+    camera_hal_delegate_ = std::make_unique<CameraHalDelegate>();
+    if (!camera_hal_delegate_->Init()) {
+      LOG(ERROR) << "Failed to initialize CameraHalDelegate";
+      camera_hal_delegate_.reset();
+      return;
+    }
     auto get_camera_info =
         base::BindRepeating(&CameraHalDelegate::GetCameraInfoFromDeviceId,
                             base::Unretained(camera_hal_delegate_.get()));
@@ -155,10 +157,7 @@
         mock_camera_module_.GetPendingRemote());
   }
 
-  void TearDown() override {
-    camera_hal_delegate_->Reset();
-    hal_delegate_thread_.Stop();
-  }
+  void TearDown() override { camera_hal_delegate_->Reset(); }
 
   void AllocateDevice() {
     ASSERT_FALSE(device_delegate_thread_.IsRunning());
@@ -535,7 +534,6 @@
   ClientType client_type_;
 
  private:
-  base::Thread hal_delegate_thread_;
   std::unique_ptr<base::RunLoop> run_loop_;
 };
 
diff --git a/media/capture/video/chromeos/camera_hal_delegate.cc b/media/capture/video/chromeos/camera_hal_delegate.cc
index f75198b..25bc8ba 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.cc
+++ b/media/capture/video/chromeos/camera_hal_delegate.cc
@@ -125,8 +125,7 @@
 
 }  // namespace
 
-CameraHalDelegate::CameraHalDelegate(
-    scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
+CameraHalDelegate::CameraHalDelegate()
     : authenticated_(false),
       camera_module_has_been_set_(
           base::WaitableEvent::ResetPolicy::MANUAL,
@@ -141,13 +140,25 @@
                             base::WaitableEvent::InitialState::NOT_SIGNALED),
       num_builtin_cameras_(0),
       camera_buffer_factory_(new CameraBufferFactory()),
-      ipc_task_runner_(std::move(ipc_task_runner)),
-      camera_module_callbacks_(this),
-      vendor_tag_ops_delegate_(ipc_task_runner_) {
+      camera_hal_ipc_thread_("CamerHalIpcThread"),
+      camera_module_callbacks_(this) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
-CameraHalDelegate::~CameraHalDelegate() = default;
+bool CameraHalDelegate::Init() {
+  if (!camera_hal_ipc_thread_.Start()) {
+    LOG(ERROR) << "CameraHalDelegate IPC thread failed to start";
+    return false;
+  }
+  ipc_task_runner_ = camera_hal_ipc_thread_.task_runner();
+  vendor_tag_ops_delegate_ =
+      std::make_unique<VendorTagOpsDelegate>(ipc_task_runner_);
+  return true;
+}
+
+CameraHalDelegate::~CameraHalDelegate() {
+  camera_hal_ipc_thread_.Stop();
+}
 
 bool CameraHalDelegate::RegisterCameraClient() {
   auto* dispatcher = CameraHalDispatcherImpl::GetInstance();
@@ -319,7 +330,8 @@
       }
 
       auto get_vendor_string = [&](const std::string& key) -> const char* {
-        const VendorTagInfo* info = vendor_tag_ops_delegate_.GetInfoByName(key);
+        const VendorTagInfo* info =
+            vendor_tag_ops_delegate_->GetInfoByName(key);
         if (info == nullptr) {
           return nullptr;
         }
@@ -407,7 +419,7 @@
   VideoCaptureControlSupport control_support;
 
   auto is_vendor_range_valid = [&](const std::string& key) -> bool {
-    const VendorTagInfo* info = vendor_tag_ops_delegate_.GetInfoByName(key);
+    const VendorTagInfo* info = vendor_tag_ops_delegate_->GetInfoByName(key);
     if (info == nullptr)
       return false;
     auto range = GetMetadataEntryAsSpan<int32_t>(
@@ -487,7 +499,7 @@
 
 const VendorTagInfo* CameraHalDelegate::GetVendorTagInfoByName(
     const std::string& full_name) {
-  return vendor_tag_ops_delegate_.GetInfoByName(full_name);
+  return vendor_tag_ops_delegate_->GetInfoByName(full_name);
 }
 
 void CameraHalDelegate::OpenDevice(
@@ -556,7 +568,7 @@
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
   camera_module_.reset();
   camera_module_callbacks_.reset();
-  vendor_tag_ops_delegate_.Reset();
+  vendor_tag_ops_delegate_->Reset();
   builtin_camera_info_updated_.Reset();
   camera_module_has_been_set_.Reset();
   has_camera_connected_.Reset();
@@ -620,7 +632,7 @@
                      base::Unretained(this)));
 
   camera_module_->GetVendorTagOps(
-      vendor_tag_ops_delegate_.MakeReceiver(),
+      vendor_tag_ops_delegate_->MakeReceiver(),
       base::BindOnce(&CameraHalDelegate::OnGotVendorTagOpsOnIpcThread,
                      base::Unretained(this)));
 }
@@ -652,7 +664,7 @@
 
 void CameraHalDelegate::OnGotVendorTagOpsOnIpcThread() {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
-  vendor_tag_ops_delegate_.Initialize();
+  vendor_tag_ops_delegate_->Initialize();
 }
 
 void CameraHalDelegate::GetCameraInfoOnIpcThread(
diff --git a/media/capture/video/chromeos/camera_hal_delegate.h b/media/capture/video/chromeos/camera_hal_delegate.h
index e0c5ef1a..69d7d84 100644
--- a/media/capture/video/chromeos/camera_hal_delegate.h
+++ b/media/capture/video/chromeos/camera_hal_delegate.h
@@ -45,9 +45,9 @@
 class CAPTURE_EXPORT CameraHalDelegate final
     : public cros::mojom::CameraModuleCallbacks {
  public:
-  // All the Mojo IPC operations happen on |ipc_task_runner|.
-  explicit CameraHalDelegate(
-      scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner);
+  CameraHalDelegate();
+  // CameraHalDelegate is functional only after this call succeeds.
+  bool Init();
 
   ~CameraHalDelegate() final;
 
@@ -72,9 +72,23 @@
       scoped_refptr<base::SingleThreadTaskRunner>
           task_runner_for_screen_observer,
       const VideoCaptureDeviceDescriptor& device_descriptor);
+
   void GetDevicesInfo(
       VideoCaptureDeviceFactory::GetDevicesInfoCallback callback);
 
+  // Returns camera pan, tilt, zoom capability support.
+  VideoCaptureControlSupport GetControlSupport(
+      const cros::mojom::CameraInfoPtr& camera_info);
+
+  // Gets the camera info of |device_id|. Returns null CameraInfoPtr on error.
+  cros::mojom::CameraInfoPtr GetCameraInfoFromDeviceId(
+      const std::string& device_id);
+
+  void EnableVirtualDevice(const std::string& device_id, bool enable);
+  void DisableAllVirtualDevices();
+
+  const VendorTagInfo* GetVendorTagInfoByName(const std::string& full_name);
+
   // Asynchronous method to open the camera device designated by |camera_id|.
   // This method may be called on any thread; |callback| will run on
   // |ipc_task_runner_|.
@@ -87,21 +101,9 @@
   // Gets camera id from device id. Returns -1 on error.
   int GetCameraIdFromDeviceId(const std::string& device_id);
 
-  // Returns camera pan, tilt, zoom capability support.
-  VideoCaptureControlSupport GetControlSupport(
-      const cros::mojom::CameraInfoPtr& camera_info);
-
-  // Gets the camera info of |device_id|. Returns null CameraInfoPtr on error.
-  cros::mojom::CameraInfoPtr GetCameraInfoFromDeviceId(
-      const std::string& device_id);
-
-  const VendorTagInfo* GetVendorTagInfoByName(const std::string& full_name);
-
-  void EnableVirtualDevice(const std::string& device_id, bool enable);
-
-  void DisableAllVirtualDevices();
-
  private:
+  friend class base::RefCountedThreadSafe<CameraHalDelegate>;
+
   void OnRegisteredCameraHalClient(int32_t result);
 
   void GetSupportedFormats(const cros::mojom::CameraInfoPtr& camera_info,
@@ -205,8 +207,12 @@
 
   std::unique_ptr<CameraBufferFactory> camera_buffer_factory_;
 
+  // The thread that all the Mojo operations of CameraHalDelegate take
+  // place.  Started in constructor and stopped in destructor.
+  base::Thread camera_hal_ipc_thread_;
+
   // The task runner where all the camera module Mojo communication takes place.
-  const scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
 
   // The Mojo proxy to access the camera module at the remote camera HAL.  Bound
   // to |ipc_task_runner_|.
@@ -219,7 +225,7 @@
 
   // An internal delegate to handle VendorTagOps mojo connection and query
   // information of vendor tags.  Bound to |ipc_task_runner_|.
-  VendorTagOpsDelegate vendor_tag_ops_delegate_;
+  std::unique_ptr<VendorTagOpsDelegate> vendor_tag_ops_delegate_;
 
   // A map from camera id to corresponding delegate instance.
   base::flat_map<int, std::unique_ptr<VideoCaptureDeviceChromeOSDelegate>>
diff --git a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc
index f9efb92c..c6c9775 100644
--- a/media/capture/video/chromeos/camera_hal_delegate_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_delegate_unittest.cc
@@ -38,7 +38,7 @@
 
 class CameraHalDelegateTest : public ::testing::Test {
  public:
-  CameraHalDelegateTest() : hal_delegate_thread_("HalDelegateThread") {}
+  CameraHalDelegateTest() {}
 
   CameraHalDelegateTest(const CameraHalDelegateTest&) = delete;
   CameraHalDelegateTest& operator=(const CameraHalDelegateTest&) = delete;
@@ -46,17 +46,17 @@
   void SetUp() override {
     VideoCaptureDeviceFactoryChromeOS::SetGpuBufferManager(
         &mock_gpu_memory_buffer_manager_);
-    hal_delegate_thread_.Start();
-    camera_hal_delegate_ =
-        std::make_unique<CameraHalDelegate>(hal_delegate_thread_.task_runner());
+    camera_hal_delegate_ = std::make_unique<CameraHalDelegate>();
+    if (!camera_hal_delegate_->Init()) {
+      LOG(ERROR) << "Failed to initialize CameraHalDelegate";
+      camera_hal_delegate_.reset();
+      return;
+    }
     camera_hal_delegate_->SetCameraModule(
         mock_camera_module_.GetPendingRemote());
   }
 
-  void TearDown() override {
-    camera_hal_delegate_->Reset();
-    hal_delegate_thread_.Stop();
-  }
+  void TearDown() override { camera_hal_delegate_->Reset(); }
 
   void Wait() {
     run_loop_ = std::make_unique<base::RunLoop>();
@@ -71,7 +71,6 @@
   unittest_internal::MockGpuMemoryBufferManager mock_gpu_memory_buffer_manager_;
 
  private:
-  base::Thread hal_delegate_thread_;
   std::unique_ptr<base::RunLoop> run_loop_;
 };
 
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
index 08ba87d..5959058e 100644
--- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
+++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.cc
@@ -22,7 +22,6 @@
 VideoCaptureDeviceFactoryChromeOS::VideoCaptureDeviceFactoryChromeOS(
     scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer)
     : task_runner_for_screen_observer_(task_runner_for_screen_observer),
-      camera_hal_ipc_thread_("CameraHalIpcThread"),
       initialized_(Init()) {}
 
 VideoCaptureDeviceFactoryChromeOS::~VideoCaptureDeviceFactoryChromeOS() {
@@ -33,7 +32,6 @@
   camera_app_device_bridge->UnsetVirtualDeviceController();
 
   camera_hal_delegate_->Reset();
-  camera_hal_ipc_thread_.Stop();
   camera_hal_delegate_.reset();
 }
 
@@ -78,18 +76,19 @@
 }
 
 bool VideoCaptureDeviceFactoryChromeOS::Init() {
-  if (!camera_hal_ipc_thread_.Start()) {
-    LOG(ERROR) << "Module thread failed to start";
-    return false;
-  }
-
   if (!CameraHalDispatcherImpl::GetInstance()->IsStarted()) {
     LOG(ERROR) << "CameraHalDispatcherImpl is not started";
     return false;
   }
 
-  camera_hal_delegate_ =
-      std::make_unique<CameraHalDelegate>(camera_hal_ipc_thread_.task_runner());
+  camera_hal_delegate_ = std::make_unique<CameraHalDelegate>();
+
+  if (!camera_hal_delegate_->Init()) {
+    LOG(ERROR) << "Failed to initialize CameraHalDelegate";
+    camera_hal_delegate_.reset();
+    return false;
+  }
+
   if (!camera_hal_delegate_->RegisterCameraClient()) {
     LOG(ERROR) << "Failed to register camera client";
     return false;
diff --git a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
index 5fad611..0abb4df 100644
--- a/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
+++ b/media/capture/video/chromeos/video_capture_device_factory_chromeos.h
@@ -48,14 +48,7 @@
   const scoped_refptr<base::SingleThreadTaskRunner>
       task_runner_for_screen_observer_;
 
-  // The thread that all the Mojo operations of |camera_hal_delegate_| take
-  // place.  Started in Init and stopped when the class instance is destroyed.
-  base::Thread camera_hal_ipc_thread_;
-
-  // Communication interface to the camera HAL.  |camera_hal_delegate_| is
-  // created on the thread on which Init is called.  All the Mojo communication
-  // that |camera_hal_delegate_| issues and receives must be sequenced through
-  // |camera_hal_ipc_thread_|.
+  // Communication interface to the camera HAL.
   std::unique_ptr<CameraHalDelegate> camera_hal_delegate_;
 
   bool initialized_;
diff --git a/media/cast/logging/stats_event_subscriber.cc b/media/cast/logging/stats_event_subscriber.cc
index 3bf1835..e9ec1317 100644
--- a/media/cast/logging/stats_event_subscriber.cc
+++ b/media/cast/logging/stats_event_subscriber.cc
@@ -64,16 +64,15 @@
   buckets_.assign(buckets_.size(), 0);
 }
 
-std::unique_ptr<base::ListValue>
-StatsEventSubscriber::SimpleHistogram::GetHistogram() const {
-  std::unique_ptr<base::ListValue> histo(new base::ListValue);
+base::Value::List StatsEventSubscriber::SimpleHistogram::GetHistogram() const {
+  base::Value::List histo;
 
-  std::unique_ptr<base::DictionaryValue> bucket(new base::DictionaryValue);
+  base::Value::Dict bucket;
 
   if (buckets_.front()) {
     base::Value::Dict bucket;
     bucket.Set(base::StringPrintf("<%" PRId64, min_), buckets_.front());
-    histo->Append(base::Value(std::move(bucket)));
+    histo.Append(std::move(bucket));
   }
 
   for (size_t i = 1; i < buckets_.size() - 1; i++) {
@@ -84,13 +83,13 @@
     int64_t upper = lower + width_ - 1;
     bucket.Set(base::StringPrintf("%" PRId64 "-%" PRId64, lower, upper),
                buckets_[i]);
-    histo->Append(base::Value(std::move(bucket)));
+    histo.Append(std::move(bucket));
   }
 
   if (buckets_.back()) {
     base::Value::Dict bucket;
     bucket.Set(base::StringPrintf(">=%" PRId64, max_), buckets_.back());
-    histo->Append(base::Value(std::move(bucket)));
+    histo.Append(std::move(bucket));
   }
   return histo;
 }
@@ -223,27 +222,25 @@
   }
 }
 
-std::unique_ptr<base::DictionaryValue> StatsEventSubscriber::GetStats() const {
+base::Value::Dict StatsEventSubscriber::GetStats() const {
   StatsMap stats_map;
   GetStatsInternal(&stats_map);
-  auto ret = std::make_unique<base::DictionaryValue>();
+  base::Value::Dict ret;
 
-  base::DictionaryValue stats;
+  base::Value::Dict stats;
   for (StatsMap::const_iterator it = stats_map.begin(); it != stats_map.end();
        ++it) {
     // Round to 3 digits after the decimal point.
-    stats.SetDouble(CastStatToString(it->first),
-                    round(it->second * 1000.0) / 1000.0);
+    stats.Set(CastStatToString(it->first), round(it->second * 1000.0) / 1000.0);
   }
 
   // Populate all histograms.
   for (auto it = histograms_.begin(); it != histograms_.end(); ++it) {
-    stats.SetKey(CastStatToString(it->first),
-                 base::Value::FromUniquePtrValue(it->second->GetHistogram()));
+    stats.Set(CastStatToString(it->first), it->second->GetHistogram());
   }
 
-  ret->SetKey(event_media_type_ == AUDIO_EVENT ? "audio" : "video",
-              std::move(stats));
+  ret.Set(event_media_type_ == AUDIO_EVENT ? "audio" : "video",
+          std::move(stats));
 
   return ret;
 }
diff --git a/media/cast/logging/stats_event_subscriber.h b/media/cast/logging/stats_event_subscriber.h
index aa14f85..89300f9 100644
--- a/media/cast/logging/stats_event_subscriber.h
+++ b/media/cast/logging/stats_event_subscriber.h
@@ -18,15 +18,11 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
+#include "base/values.h"
 #include "media/cast/logging/logging_defines.h"
 #include "media/cast/logging/raw_event_subscriber.h"
 #include "media/cast/logging/receiver_time_offset_estimator.h"
 
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
 namespace media {
 namespace cast {
 
@@ -54,7 +50,7 @@
   // The inner dictionary consists of string - double entries, where the string
   // describes the name of the stat, and the double describes
   // the value of the stat. See CastStat and StatsMap below.
-  std::unique_ptr<base::DictionaryValue> GetStats() const;
+  base::Value::Dict GetStats() const;
 
   // Resets stats in this object.
   void Reset();
@@ -109,7 +105,7 @@
 
     void Reset();
 
-    std::unique_ptr<base::ListValue> GetHistogram() const;
+    base::Value::List GetHistogram() const;
 
    private:
     int64_t min_;
diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc
index b340c6a..c37424b 100644
--- a/media/cast/logging/stats_event_subscriber_unittest.cc
+++ b/media/cast/logging/stats_event_subscriber_unittest.cc
@@ -524,11 +524,10 @@
   EXPECT_DOUBLE_EQ(it->second, static_cast<double>(num_packets_rtx_rejected));
 }
 
-bool CheckHistogramHasValue(base::ListValue* values,
+bool CheckHistogramHasValue(const base::Value::List& values,
                             const std::string& bucket,
                             int expected_count) {
-  for (size_t i = 0; i < values->GetListDeprecated().size(); ++i) {
-    const base::Value& value = values->GetListDeprecated()[i];
+  for (const base::Value& value : values) {
     if (!value.is_dict() || !value.FindKey(bucket))
       continue;
     absl::optional<int> bucket_count = value.FindIntKey(bucket);
@@ -627,47 +626,47 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(playout_event));
 
   StatsEventSubscriber::SimpleHistogram* histogram;
-  std::unique_ptr<base::ListValue> values;
+  base::Value::List values;
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::CAPTURE_LATENCY_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "10-14", 10));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "10-14", 10));
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::ENCODE_TIME_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "15-19", 10));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "15-19", 10));
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::QUEUEING_LATENCY_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1));
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1));
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "100-119", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "200-219", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "300-319", 1));
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::NETWORK_LATENCY_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1));
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "200-219", 1));
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "300-319", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "100-119", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "200-219", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "300-319", 1));
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::PACKET_LATENCY_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "400-419", 3));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "400-419", 3));
 
   histogram = subscriber_->GetHistogramForTesting(
       StatsEventSubscriber::LATE_FRAME_MS_HISTO);
   ASSERT_TRUE(histogram);
   values = histogram->GetHistogram();
-  EXPECT_TRUE(CheckHistogramHasValue(values.get(), "100-119", 1));
+  EXPECT_TRUE(CheckHistogramHasValue(values, "100-119", 1));
 }
 
 }  // namespace cast
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index e6a4cf8..14d28e8 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -108,17 +108,16 @@
   cast_environment->logger()->Unsubscribe(audio_stats_subscriber.get());
   cast_environment->logger()->Unsubscribe(estimator.get());
 
-  std::unique_ptr<base::DictionaryValue> stats =
-      video_stats_subscriber->GetStats();
+  base::Value::Dict stats = video_stats_subscriber->GetStats();
   std::string json;
   base::JSONWriter::WriteWithOptions(
-      *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   VLOG(0) << "Video stats: " << json;
 
   stats = audio_stats_subscriber->GetStats();
   json.clear();
   base::JSONWriter::WriteWithOptions(
-      *stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+      stats, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
   VLOG(0) << "Audio stats: " << json;
 }
 
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index 5bc5e17..c97d695 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -1065,7 +1065,6 @@
     vaapi_wrapper_->DestroyContext();
 
   available_encode_surfaces_.clear();
-  available_va_buffer_ids_.clear();
 
   if (vpp_vaapi_wrapper_)
     vpp_vaapi_wrapper_->DestroyContext();
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.h b/media/gpu/vaapi/vaapi_video_encode_accelerator.h
index a00720a..13a062f 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.h
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.h
@@ -278,9 +278,6 @@
   // indexed by a layer resolution.
   EncodeSurfacesCountMap encode_surfaces_count_;
 
-  // VA buffers for coded frames.
-  std::vector<VABufferID> available_va_buffer_ids_;
-
   // Queue of input frames to be encoded.
   base::queue<std::unique_ptr<InputFrameRef>> input_queue_;
 
diff --git a/net/socket/tcp_client_socket.cc b/net/socket/tcp_client_socket.cc
index 645d9b40..93c86a4 100644
--- a/net/socket/tcp_client_socket.cc
+++ b/net/socket/tcp_client_socket.cc
@@ -62,14 +62,12 @@
     std::unique_ptr<TCPSocket> unconnected_socket,
     const AddressList& addresses,
     NetworkQualityEstimator* network_quality_estimator)
-    : TCPClientSocket(
-          std::move(unconnected_socket),
-          addresses,
-          -1 /* current_address_index */,
-          nullptr /* bind_address */,
-          network_quality_estimator,
-          // TODO(https://crbug.com/1295460): Pass through network handle
-          NetworkChangeNotifier::kInvalidNetworkHandle) {}
+    : TCPClientSocket(std::move(unconnected_socket),
+                      addresses,
+                      -1 /* current_address_index */,
+                      nullptr /* bind_address */,
+                      network_quality_estimator,
+                      NetworkChangeNotifier::kInvalidNetworkHandle) {}
 
 TCPClientSocket::~TCPClientSocket() {
   Disconnect();
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index d8a383a6..dc41e47e 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -357,7 +357,7 @@
   }
 
   if (bound_network_ != NetworkChangeNotifier::kInvalidNetworkHandle) {
-    DCHECK(!client_socket_factory_);
+    DCHECK(!client_socket_factory_raw_);
     DCHECK(!host_resolver_);
     DCHECK(!host_resolver_manager_);
     DCHECK(!host_resolver_factory_);
@@ -394,6 +394,10 @@
     http_network_session_params_.ignore_ip_address_changes = true;
   }
 
+  if (client_socket_factory_) {
+    storage->set_client_socket_factory(std::move(client_socket_factory_));
+  }
+
   if (host_resolver_) {
     DCHECK(host_mapping_rules_.empty());
     DCHECK(!host_resolver_manager_);
@@ -567,7 +571,7 @@
   SetHttpNetworkSessionComponents(
       context.get(), &network_session_context,
       suppress_setting_socket_performance_watcher_factory_for_testing_,
-      client_socket_factory_);
+      client_socket_factory_raw_);
 
   storage->set_http_network_session(std::make_unique<HttpNetworkSession>(
       http_network_session_params_, network_session_context));
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 4b40d8f..f11f9ce3 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -40,6 +40,7 @@
 #include "net/network_error_logging/network_error_logging_service.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/proxy_resolution/proxy_resolution_service.h"
+#include "net/socket/client_socket_factory.h"
 #include "net/ssl/ssl_config_service.h"
 #include "net/third_party/quiche/src/quiche/quic/core/quic_packets.h"
 #include "net/url_request/url_request_job_factory.h"
@@ -343,6 +344,14 @@
     set_client_socket_factory(client_socket_factory_for_testing);
   }
 
+  // Sets a ClientSocketFactory when the network service sandbox is enabled. The
+  // unique_ptr is moved to a URLRequestContextStorage once Build() is called.
+  void set_client_socket_factory(
+      std::unique_ptr<ClientSocketFactory> client_socket_factory) {
+    set_client_socket_factory(client_socket_factory.get());
+    client_socket_factory_ = std::move(client_socket_factory);
+  }
+
   // Binds the context to `network`. All requests scheduled through the context
   // built by this builder will be sent using `network`. Requests will fail if
   // `network` disconnects.
@@ -389,7 +398,7 @@
   // URLRequestContext that will be built.
   // `client_socket_factory` must outlive the context.
   void set_client_socket_factory(ClientSocketFactory* client_socket_factory) {
-    client_socket_factory_ = client_socket_factory;
+    client_socket_factory_raw_ = client_socket_factory;
   }
 
   bool enable_brotli_ = false;
@@ -433,6 +442,7 @@
   std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer_;
   std::unique_ptr<SCTAuditingDelegate> sct_auditing_delegate_;
   std::unique_ptr<QuicContext> quic_context_;
+  std::unique_ptr<ClientSocketFactory> client_socket_factory_ = nullptr;
 #if BUILDFLAG(ENABLE_REPORTING)
   std::unique_ptr<ReportingService> reporting_service_;
   std::unique_ptr<ReportingPolicy> reporting_policy_;
@@ -445,7 +455,7 @@
   std::map<std::string, std::unique_ptr<URLRequestJobFactory::ProtocolHandler>>
       protocol_handlers_;
 
-  raw_ptr<ClientSocketFactory> client_socket_factory_ = nullptr;
+  raw_ptr<ClientSocketFactory> client_socket_factory_raw_ = nullptr;
 };
 
 }  // namespace net
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 518ab2ff..2fe471c 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -81,6 +81,7 @@
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
+#include "services/network/brokered_client_socket_factory.h"
 #include "services/network/cookie_manager.h"
 #include "services/network/cors/cors_url_loader_factory.h"
 #include "services/network/disk_cache/mojo_backend_file_operations_factory.h"
@@ -2570,6 +2571,12 @@
   builder.set_first_party_sets_enabled(
       first_party_sets_access_delegate_.is_enabled());
 
+  if (params_->socket_broker) {
+    builder.set_client_socket_factory(
+        std::make_unique<BrokeredClientSocketFactory>(
+            std::move(params_->socket_broker)));
+  }
+
   // If `require_network_isolation_key_` is true, but the features that can
   // trigger another URLRequest are not set to respect NetworkIsolationKeys,
   // the URLRequests that they create might not have a NIK, so only set the
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index d049833f..0a37668 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -42,6 +42,7 @@
 import "services/network/public/mojom/reporting_service.mojom";
 import "services/network/public/mojom/restricted_cookie_manager.mojom";
 import "services/network/public/mojom/site_for_cookies.mojom";
+import "services/network/public/mojom/socket_broker.mojom";
 import "services/network/public/mojom/ssl_config.mojom";
 import "services/network/public/mojom/tcp_socket.mojom";
 import "services/network/public/mojom/transferable_directory.mojom";
@@ -405,6 +406,10 @@
   // settings.
   pending_remote<ProxyErrorClient>? proxy_error_client;
 
+  // Broker used by the network service sandbox to create sockets in
+  // the browser. Set when the sandbox is enabled.
+  pending_remote<SocketBroker>? socket_broker;
+
   // When PAC quick checking is enabled, DNS lookups for PAC script's host are
   // timed out aggressively. This prevents hanging all network request on DNS
   // lookups that are slow or are blockholed, at the cost of making it more
diff --git a/storage/browser/file_system/obfuscated_file_util.cc b/storage/browser/file_system/obfuscated_file_util.cc
index f3463199..1b590b09 100644
--- a/storage/browser/file_system/obfuscated_file_util.cc
+++ b/storage/browser/file_system/obfuscated_file_util.cc
@@ -206,7 +206,8 @@
   }
 
   raw_ptr<SandboxDirectoryDatabase> db_;
-  raw_ptr<FileSystemOperationContext> context_;
+  // TODO(crbug.com/1298696): Breaks storage_unittests.
+  raw_ptr<FileSystemOperationContext, DegradeToNoOpWhenMTE> context_;
   raw_ptr<ObfuscatedFileUtil> obfuscated_file_util_;
   FileSystemURL root_url_;
   bool recursive_;
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index ec73dbc..c5f609b 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -8330,15 +8330,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8449,7 +8449,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -8840,15 +8840,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -8959,7 +8959,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 13958ea..eda9e2b 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46508,15 +46508,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -46627,7 +46627,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47018,15 +47018,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47137,7 +47137,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47532,15 +47532,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -47651,7 +47651,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48042,15 +48042,15 @@
       {
         "args": [
           "--additional-apk=apks/ChromePublic.apk",
-          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/AOSP_SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48161,7 +48161,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -48624,15 +48624,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -48743,7 +48743,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49134,15 +49134,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49253,7 +49253,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -49716,15 +49716,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
-          "--client-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--implementation-outdir",
           ".",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--client-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--client-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -49835,7 +49835,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -50226,15 +50226,15 @@
       {
         "args": [
           "--additional-apk=apks/WebLayerShellSystemWebView.apk",
-          "--webview-apk-path=apks/SystemWebView.apk",
           "--test-runner-outdir",
           ".",
           "--client-outdir",
           ".",
-          "--implementation-outdir",
-          "../../weblayer_instrumentation_test_M103/out/Release",
           "--test-expectations",
           "../../weblayer/browser/android/javatests/skew/expectations.txt",
+          "--webview-apk-path=apks/SystemWebView.apk",
+          "--implementation-outdir",
+          "../../weblayer_instrumentation_test_M103/out/Release",
           "--impl-version=103",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
@@ -50345,7 +50345,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M104",
-              "revision": "version:104.0.5112.30"
+              "revision": "version:104.0.5112.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 96038b02..b8a46f2 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -5688,21 +5688,21 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -5715,7 +5715,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
@@ -5853,21 +5853,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -5879,7 +5879,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "args": [
@@ -5999,21 +5999,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -6025,7 +6025,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index eb5c0c35..a1578427 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -92974,21 +92974,21 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
@@ -92996,7 +92996,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
@@ -93109,28 +93109,28 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "args": [
@@ -93230,28 +93230,28 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
@@ -94589,20 +94589,20 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -94616,7 +94616,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "merge": {
@@ -94754,20 +94754,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -94780,7 +94780,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "args": [
@@ -94900,20 +94900,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -94926,7 +94926,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "merge": {
@@ -96422,20 +96422,20 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -96449,7 +96449,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "merge": {
@@ -96587,20 +96587,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -96613,7 +96613,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "args": [
@@ -96733,20 +96733,20 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -96759,7 +96759,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "merge": {
@@ -97494,20 +97494,20 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -97520,7 +97520,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       }
     ]
   },
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index c44583e4..b2596a9 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -20874,21 +20874,21 @@
       {
         "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_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5152.0",
+        "name": "interactive_ui_tests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -20901,7 +20901,7 @@
         },
         "test": "interactive_ui_tests",
         "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
@@ -21039,21 +21039,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -21065,7 +21065,7 @@
         },
         "test": "lacros_chrome_browsertests",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "args": [
@@ -21185,21 +21185,21 @@
       {
         "args": [
           "--test-launcher-filter-file=../../testing/buildbot/filters/linux-lacros.lacros_chrome_browsertests.skew.filter",
-          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome"
+          "--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome"
         ],
         "isolate_profile_data": true,
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
         },
-        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5152.0",
+        "name": "lacros_chrome_browsertests_run_in_series Lacros version skew testing ash 105.0.5153.0",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "cipd_packages": [
             {
               "cipd_package": "chromium/testing/linux-ash-chromium/x86_64/ash.zip",
-              "location": "lacros_version_skew_tests_v105.0.5152.0",
-              "revision": "version:105.0.5152.0"
+              "location": "lacros_version_skew_tests_v105.0.5153.0",
+              "revision": "version:105.0.5153.0"
             }
           ],
           "dimension_sets": [
@@ -21211,7 +21211,7 @@
         },
         "test": "lacros_chrome_browsertests_run_in_series",
         "test_id_prefix": "ninja://chrome/test:lacros_chrome_browsertests_run_in_series/",
-        "variant_id": "Lacros version skew testing ash 105.0.5152.0"
+        "variant_id": "Lacros version skew testing ash 105.0.5153.0"
       },
       {
         "isolate_profile_data": true,
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 36c1e5d0..ddc267c 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -22,15 +22,15 @@
   },
   'LACROS_VERSION_SKEW_CANARY': {
     'args': [
-      '--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5152.0/test_ash_chrome',
+      '--ash-chrome-path-override=../../lacros_version_skew_tests_v105.0.5153.0/test_ash_chrome',
     ],
-    'identifier': 'Lacros version skew testing ash 105.0.5152.0',
+    'identifier': 'Lacros version skew testing ash 105.0.5153.0',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/linux-ash-chromium/x86_64/ash.zip',
-          'location': 'lacros_version_skew_tests_v105.0.5152.0',
-          'revision': 'version:105.0.5152.0',
+          'location': 'lacros_version_skew_tests_v105.0.5153.0',
+          'revision': 'version:105.0.5153.0',
         },
       ],
     },
@@ -546,23 +546,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M104',
-          'revision': 'version:104.0.5112.30'
+          'revision': 'version:104.0.5112.31'
         }
       ]
     }
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--implementation-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--impl-version=103',
+      '--webview-apk-path=apks/AOSP_SystemWebView.apk',
+      '--implementation-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--impl-version=103'
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -570,10 +570,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.102',
+          'revision': 'version:103.0.5060.102'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_10_AND_M_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
@@ -690,23 +690,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M104',
-          'revision': 'version:104.0.5112.30'
+          'revision': 'version:104.0.5112.31'
         }
       ]
     }
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
       '--client-outdir',
       '.',
-      '--implementation-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--impl-version=103',
+      '--webview-apk-path=apks/SystemWebView.apk',
+      '--implementation-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--impl-version=103'
     ],
     'identifier': 'with_impl_from_103',
     'swarming': {
@@ -714,10 +714,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.102',
+          'revision': 'version:103.0.5060.102'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_IMPL_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
@@ -834,23 +834,23 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M104',
-          'revision': 'version:104.0.5112.30'
+          'revision': 'version:104.0.5112.31'
         }
       ]
     }
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_ONE_MILESTONE': {
     'args': [
-      '--webview-apk-path=apks/SystemWebView.apk',
       '--test-runner-outdir',
       '.',
-      '--client-outdir',
-      '../../weblayer_instrumentation_test_M103/out/Release',
       '--implementation-outdir',
       '.',
       '--test-expectations',
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
-      '--client-version=103',
+      '--webview-apk-path=apks/SystemWebView.apk',
+      '--client-outdir',
+      '../../weblayer_instrumentation_test_M103/out/Release',
+      '--client-version=103'
     ],
     'identifier': 'with_client_from_103',
     'swarming': {
@@ -858,10 +858,10 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M103',
-          'revision': 'version:103.0.5060.102',
+          'revision': 'version:103.0.5060.102'
         }
-      ],
-    },
+      ]
+    }
   },
   'WEBLAYER_CLIENT_SKEW_TESTS_NTH_MINUS_TWO_MILESTONE': {
     'args': [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 931edff1..ea5068c 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -9307,6 +9307,21 @@
             ]
         }
     ],
+    "VirtualKeyboardMultitouch": [
+        {
+            "platforms": [
+                "chromeos"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "VirtualKeyboardMultitouch"
+                    ]
+                }
+            ]
+        }
+    ],
     "VisualFeaturesInCsppPings": [
         {
             "platforms": [
diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc
index 2b490c6..ea903c6 100644
--- a/third_party/blink/renderer/core/frame/dom_window.cc
+++ b/third_party/blink/renderer/core/frame/dom_window.cc
@@ -581,18 +581,15 @@
 
   // Iframes are allowed to trigger reports, only when they are same-origin with
   // their top-level document.
-  // TODO(crbug.com/1318055): With MPArch there may be multiple main frames
-  // so we should use IsCrossOriginToOutermostMainFrame when we intend to check
-  // if any embedded frame (eg, iframe or fenced frame) is cross-origin with
-  // respect to the outermost main frame. Follow up to confirm correctness.
   if (accessing_frame->IsCrossOriginToOutermostMainFrame())
     return;
 
-  // See https://crbug.com/1183571
-  // We assumed accessing_frame->IsCrossOriginToNearestMainFrame() implies
-  // accessing_frame->Tree().Top() to be a LocalFrame. This might not be the
-  // case after all, some crashes are reported. This block speculatively returns
-  // early to avoid crashing.
+  // We returned early if accessing_frame->IsCrossOriginToOutermostMainFrame()
+  // was true. This means we are not in a fenced frame and that the nearest main
+  // frame is same-origin. This generally implies accessing_frame->Tree().Top()
+  // to be a LocalFrame. On rare occasions same-origin frames in a page might
+  // not share a process. This block speculatively returns early to avoid
+  // crashing.
   // TODO(https://crbug.com/1183571): Check if crashes are still happening and
   // remove this block.
   if (!accessing_frame->Tree().Top().IsLocalFrame()) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
index 3a3102db..da2292c 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_combine.cc
@@ -233,7 +233,9 @@
     // supported in vertical flow and text-combine is only for vertical flow.
     const LayoutRect decoration_rect =
         NGInkOverflow::ComputeTextDecorationOverflow(
-            style, style.GetFont(), ink_overflow, /* inline_context */ nullptr);
+            style, style.GetFont(),
+            /* offset_in_container */ PhysicalOffset(), ink_overflow,
+            /* inline_context */ nullptr);
     ink_overflow.Unite(decoration_rect);
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index e445fcb..96792fa 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -872,8 +872,8 @@
       NGInlinePaintContext::ScopedInlineItem scoped_inline_item(*this,
                                                                 inline_context);
       ink_overflow_type_ = ink_overflow_.SetTextInkOverflow(
-          InkOverflowType(), paint_info, Style(), Size(), inline_context,
-          self_and_contents_rect_out);
+          InkOverflowType(), paint_info, Style(), RectInContainerFragment(),
+          inline_context, self_and_contents_rect_out);
       return;
     }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
index fd1b806..3e71c556 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.cc
@@ -343,20 +343,20 @@
     Type type,
     const NGTextFragmentPaintInfo& text_info,
     const ComputedStyle& style,
-    const PhysicalSize& size,
+    const PhysicalRect& rect_in_container,
     const NGInlinePaintContext* inline_context,
     PhysicalRect* ink_overflow_out) {
   CheckType(type);
   DCHECK(type == kNotSet || type == kInvalidated);
   absl::optional<PhysicalRect> ink_overflow = ComputeTextInkOverflow(
-      text_info, style, style.GetFont(), size, inline_context);
+      text_info, style, style.GetFont(), rect_in_container, inline_context);
   if (!ink_overflow) {
-    *ink_overflow_out = {PhysicalOffset(), size};
+    *ink_overflow_out = {PhysicalOffset(), rect_in_container.size};
     return Reset(type);
   }
   ink_overflow->ExpandEdgesToPixelBoundaries();
   *ink_overflow_out = *ink_overflow;
-  return SetSelf(type, *ink_overflow, size);
+  return SetSelf(type, *ink_overflow, rect_in_container.size);
 }
 
 NGInkOverflow::Type NGInkOverflow::SetSvgTextInkOverflow(
@@ -381,7 +381,8 @@
                          LayoutUnit(rect.height() / length_adjust_scale));
   // No |inline_context| because the decoration box is not supported for SVG.
   absl::optional<PhysicalRect> ink_overflow = ComputeTextInkOverflow(
-      text_info, style, scaled_font, item_size, /* inline_context */ nullptr);
+      text_info, style, scaled_font, PhysicalRect(PhysicalOffset(), item_size),
+      /* inline_context */ nullptr);
   const bool needs_transform =
       scaling_factor != 1.0f || !transform.IsIdentity();
   PhysicalSize unscaled_size = PhysicalSize::FromSizeFRound(rect.size());
@@ -429,7 +430,7 @@
     const NGTextFragmentPaintInfo& text_info,
     const ComputedStyle& style,
     const Font& scaled_font,
-    const PhysicalSize& size,
+    const PhysicalRect& rect_in_container,
     const NGInlinePaintContext* inline_context) {
   // Glyph bounds is in logical coordinate, origin at the alphabetic baseline.
   const gfx::RectF text_ink_bounds = scaled_font.TextInkBounds(text_info);
@@ -450,12 +451,15 @@
   // so compute text decoration overflow first.
   if (!style.AppliedTextDecorations().IsEmpty() && scaled_font.PrimaryFont()) {
     LayoutRect decoration_rect = ComputeTextDecorationOverflow(
-        style, scaled_font, ink_overflow, inline_context);
+        style, scaled_font, rect_in_container.offset, ink_overflow,
+        inline_context);
     ink_overflow.Unite(decoration_rect);
   }
 
-  if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone)
-    ink_overflow = ComputeEmphasisMarkOverflow(style, size, ink_overflow);
+  if (style.GetTextEmphasisMark() != TextEmphasisMark::kNone) {
+    ink_overflow = ComputeEmphasisMarkOverflow(style, rect_in_container.size,
+                                               ink_overflow);
+  }
 
   const WritingMode writing_mode = style.GetWritingMode();
   if (ShadowList* text_shadow = style.TextShadow()) {
@@ -469,15 +473,16 @@
   }
 
   PhysicalRect local_ink_overflow =
-      WritingModeConverter({writing_mode, TextDirection::kLtr}, size)
+      WritingModeConverter({writing_mode, TextDirection::kLtr},
+                           rect_in_container.size)
           .ToPhysical(LogicalRect(ink_overflow));
 
   // Uniting the frame rect ensures that non-ink spaces such side bearings, or
   // even space characters, are included in the visual rect for decorations.
-  if (!HasOverflow(local_ink_overflow, size))
+  if (!HasOverflow(local_ink_overflow, rect_in_container.size))
     return absl::nullopt;
 
-  local_ink_overflow.Unite({{}, size});
+  local_ink_overflow.Unite({{}, rect_in_container.size});
   return local_ink_overflow;
 }
 
@@ -509,12 +514,10 @@
 LayoutRect NGInkOverflow::ComputeTextDecorationOverflow(
     const ComputedStyle& style,
     const Font& scaled_font,
+    const PhysicalOffset& offset_in_container,
     const LayoutRect& ink_overflow,
     const NGInlinePaintContext* inline_context) {
   DCHECK(!style.AppliedTextDecorations().IsEmpty());
-  // Use a zero offset because all offsets
-  // are applied to the ink overflow after it has been computed.
-  PhysicalOffset offset;
   // Ideally we should pass MinimumThickness1(false) if this function is
   // called for NGFragmentItem::kSvgText. However it requires to add arguments
   // to some functions.
@@ -522,7 +525,7 @@
   // because it just makes the resultant ink overflow slightly larger.
   const MinimumThickness1 kMinimumThicknessIsOne(true);
   TextDecorationInfo decoration_info(
-      offset, ink_overflow.Width(), style, inline_context,
+      offset_in_container, ink_overflow.Width(), style, inline_context,
       /* selection_text_decoration */ absl::nullopt, &scaled_font,
       kMinimumThicknessIsOne);
   NGTextDecorationOffset decoration_offset(decoration_info.TargetStyle(),
@@ -548,6 +551,8 @@
       accumulated_bound.Union(decoration_info.Bounds());
     }
   }
+  // Adjust the container coordinate system to the local coordinate system.
+  accumulated_bound -= gfx::Vector2dF(offset_in_container);
   return EnclosingLayoutRect(accumulated_bound);
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
index ee86ae1..57149671 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h
@@ -117,7 +117,7 @@
   Type SetTextInkOverflow(Type type,
                           const NGTextFragmentPaintInfo& text_info,
                           const ComputedStyle& style,
-                          const PhysicalSize& size,
+                          const PhysicalRect& rect_in_container,
                           const NGInlinePaintContext* inline_context,
                           PhysicalRect* ink_overflow_out);
 
@@ -138,7 +138,7 @@
       const NGTextFragmentPaintInfo& text_info,
       const ComputedStyle& style,
       const Font& scaled_font,
-      const PhysicalSize& size,
+      const PhysicalRect& rect_in_container,
       const NGInlinePaintContext* inline_context);
 
   // Returns ink-overflow with emphasis mark overflow in logical direction.
@@ -155,6 +155,7 @@
   static LayoutRect ComputeTextDecorationOverflow(
       const ComputedStyle& style,
       const Font& scaled_font,
+      const PhysicalOffset& offset_in_container,
       const LayoutRect& ink_overflow,
       const NGInlinePaintContext* inline_context);
 
diff --git a/third_party/blink/renderer/core/loader/beacon_data.cc b/third_party/blink/renderer/core/loader/beacon_data.cc
new file mode 100644
index 0000000..f664d145
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/beacon_data.cc
@@ -0,0 +1,152 @@
+#include "third_party/blink/renderer/core/loader/beacon_data.h"
+
+#include "third_party/blink/renderer/core/fileapi/blob.h"
+#include "third_party/blink/renderer/core/fileapi/file.h"
+#include "third_party/blink/renderer/core/html/forms/form_data.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
+#include "third_party/blink/renderer/core/url/url_search_params.h"
+#include "third_party/blink/renderer/platform/loader/cors/cors.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
+
+namespace blink {
+
+BeaconString::BeaconString(const String& data)
+    : data_(data), content_type_("text/plain;charset=UTF-8") {}
+
+uint64_t BeaconString::size() const {
+  return data_.CharactersSizeInBytes();
+}
+
+scoped_refptr<EncodedFormData> BeaconString::GetEncodedFormData() const {
+  return EncodedFormData::Create(data_.Utf8());
+}
+
+void BeaconString::Serialize(ResourceRequest& request) const {
+  request.SetHttpBody(GetEncodedFormData());
+  if (!data_.IsNull()) {
+    request.SetHTTPContentType(GetContentType());
+  }
+}
+
+BeaconBlob::BeaconBlob(Blob* data) : data_(data) {
+  const String& blob_type = data_->type();
+  if (!blob_type.IsEmpty() && ParsedContentType(blob_type).IsValid())
+    content_type_ = AtomicString(blob_type);
+}
+
+uint64_t BeaconBlob::size() const {
+  return data_->size();
+}
+
+scoped_refptr<EncodedFormData> BeaconBlob::GetEncodedFormData() const {
+  DCHECK(data_);
+
+  scoped_refptr<EncodedFormData> entity_body = EncodedFormData::Create();
+  if (data_->HasBackingFile()) {
+    entity_body->AppendFile(To<File>(data_)->GetPath(),
+                            To<File>(data_)->LastModifiedTime());
+  } else {
+    entity_body->AppendBlob(data_->Uuid(), data_->GetBlobDataHandle());
+  }
+
+  return entity_body;
+}
+
+void BeaconBlob::Serialize(ResourceRequest& request) const {
+  request.SetHttpBody(GetEncodedFormData());
+
+  if (!GetContentType().IsEmpty()) {
+    if (!cors::IsCorsSafelistedContentType(GetContentType())) {
+      request.SetMode(network::mojom::blink::RequestMode::kCors);
+    }
+    request.SetHTTPContentType(GetContentType());
+  }
+}
+
+BeaconDOMArrayBufferView::BeaconDOMArrayBufferView(DOMArrayBufferView* data)
+    : data_(data) {
+  CHECK(base::CheckedNumeric<wtf_size_t>(data->byteLength()).IsValid())
+      << "EncodedFormData::Create cannot deal with huge ArrayBuffers.";
+}
+
+uint64_t BeaconDOMArrayBufferView::size() const {
+  return data_->byteLength();
+}
+
+scoped_refptr<EncodedFormData> BeaconDOMArrayBufferView::GetEncodedFormData()
+    const {
+  DCHECK(data_);
+
+  return EncodedFormData::Create(
+      data_->BaseAddress(),
+      base::checked_cast<wtf_size_t>(data_->byteLength()));
+}
+
+void BeaconDOMArrayBufferView::Serialize(ResourceRequest& request) const {
+  request.SetHttpBody(GetEncodedFormData());
+}
+
+BeaconDOMArrayBuffer::BeaconDOMArrayBuffer(DOMArrayBuffer* data) : data_(data) {
+  CHECK(base::CheckedNumeric<wtf_size_t>(data->ByteLength()).IsValid())
+      << "EncodedFormData::Create cannot deal with huge ArrayBuffers.";
+}
+
+uint64_t BeaconDOMArrayBuffer::size() const {
+  return data_->ByteLength();
+}
+
+scoped_refptr<EncodedFormData> BeaconDOMArrayBuffer::GetEncodedFormData()
+    const {
+  DCHECK(data_);
+
+  return EncodedFormData::Create(
+      data_->Data(), base::checked_cast<wtf_size_t>(data_->ByteLength()));
+}
+
+void BeaconDOMArrayBuffer::Serialize(ResourceRequest& request) const {
+  request.SetHttpBody(GetEncodedFormData());
+}
+
+BeaconURLSearchParams::BeaconURLSearchParams(URLSearchParams* data)
+    : data_(data),
+      content_type_("application/x-www-form-urlencoded;charset=UTF-8") {}
+
+uint64_t BeaconURLSearchParams::size() const {
+  return data_->toString().CharactersSizeInBytes();
+}
+
+scoped_refptr<EncodedFormData> BeaconURLSearchParams::GetEncodedFormData()
+    const {
+  DCHECK(data_);
+
+  return data_->ToEncodedFormData();
+}
+
+void BeaconURLSearchParams::Serialize(ResourceRequest& request) const {
+  DCHECK(data_);
+
+  request.SetHttpBody(GetEncodedFormData());
+  request.SetHTTPContentType(GetContentType());
+}
+
+BeaconFormData::BeaconFormData(FormData* data)
+    : data_(data),
+      entity_body_(data_->EncodeMultiPartFormData()),
+      content_type_(String("multipart/form-data; boundary=") +
+                    entity_body_->Boundary().data()) {}
+
+uint64_t BeaconFormData::size() const {
+  return entity_body_->SizeInBytes();
+}
+
+scoped_refptr<EncodedFormData> BeaconFormData::GetEncodedFormData() const {
+  return entity_body_;
+}
+
+void BeaconFormData::Serialize(ResourceRequest& request) const {
+  request.SetHttpBody(GetEncodedFormData());
+  request.SetHTTPContentType(GetContentType());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/beacon_data.h b/third_party/blink/renderer/core/loader/beacon_data.h
new file mode 100644
index 0000000..2f63cce1
--- /dev/null
+++ b/third_party/blink/renderer/core/loader/beacon_data.h
@@ -0,0 +1,126 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BEACON_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BEACON_DATA_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class Blob;
+class DOMArrayBufferView;
+class DOMArrayBuffer;
+class EncodedFormData;
+class FormData;
+class ResourceRequest;
+class URLSearchParams;
+
+// BeaconData handles beacon data serialization.
+class BeaconData {
+  STACK_ALLOCATED();
+
+ public:
+  virtual void Serialize(ResourceRequest&) const = 0;
+
+ protected:
+  virtual uint64_t size() const = 0;
+  virtual const AtomicString GetContentType() const = 0;
+  virtual scoped_refptr<EncodedFormData> GetEncodedFormData() const = 0;
+};
+
+class BeaconString final : public BeaconData {
+ public:
+  explicit BeaconString(const String& data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return content_type_; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  const String data_;
+  AtomicString content_type_;
+};
+
+class BeaconBlob final : public BeaconData {
+ public:
+  explicit BeaconBlob(Blob* data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return content_type_; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  Blob* const data_;
+  AtomicString content_type_;
+};
+
+class BeaconDOMArrayBufferView final : public BeaconData {
+ public:
+  explicit BeaconDOMArrayBufferView(DOMArrayBufferView* data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return g_null_atom; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  DOMArrayBufferView* const data_;
+};
+
+class BeaconDOMArrayBuffer final : public BeaconData {
+ public:
+  explicit BeaconDOMArrayBuffer(DOMArrayBuffer* data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return g_null_atom; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  DOMArrayBuffer* const data_;
+};
+
+class BeaconURLSearchParams final : public BeaconData {
+ public:
+  explicit BeaconURLSearchParams(URLSearchParams* data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return content_type_; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  URLSearchParams* const data_;
+  AtomicString content_type_;
+};
+
+class BeaconFormData final : public BeaconData {
+ public:
+  explicit BeaconFormData(FormData* data);
+  void Serialize(ResourceRequest& request) const override;
+
+ protected:
+  uint64_t size() const override;
+  const AtomicString GetContentType() const override { return content_type_; }
+  scoped_refptr<EncodedFormData> GetEncodedFormData() const override;
+
+ private:
+  FormData* const data_;
+  scoped_refptr<EncodedFormData> entity_body_;
+  AtomicString content_type_;
+};
+
+}  // namespace blink
+
+#endif  // #define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_BEACON_DATA_H_
diff --git a/third_party/blink/renderer/core/loader/build.gni b/third_party/blink/renderer/core/loader/build.gni
index 2800208d..1d056ee5 100644
--- a/third_party/blink/renderer/core/loader/build.gni
+++ b/third_party/blink/renderer/core/loader/build.gni
@@ -11,6 +11,8 @@
   "back_forward_cache_loader_helper_impl.h",
   "base_fetch_context.cc",
   "base_fetch_context.h",
+  "beacon_data.cc",
+  "beacon_data.h",
   "cookie_jar.cc",
   "cookie_jar.h",
   "cross_thread_resource_timing_info_copier.cc",
diff --git a/third_party/blink/renderer/core/loader/ping_loader.cc b/third_party/blink/renderer/core/loader/ping_loader.cc
index a4101ba..2def049c 100644
--- a/third_party/blink/renderer/core/loader/ping_loader.cc
+++ b/third_party/blink/renderer/core/loader/ping_loader.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/html/forms/form_data.h"
+#include "third_party/blink/renderer/core/loader/beacon_data.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
 #include "third_party/blink/renderer/core/url/url_search_params.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
@@ -63,173 +64,10 @@
 
 namespace {
 
-class Beacon {
-  STACK_ALLOCATED();
-
- public:
-  virtual void Serialize(ResourceRequest&) const = 0;
-  virtual uint64_t size() const = 0;
-  virtual const AtomicString GetContentType() const = 0;
-};
-
-class BeaconString final : public Beacon {
- public:
-  explicit BeaconString(const String& data) : data_(data) {}
-
-  uint64_t size() const override { return data_.CharactersSizeInBytes(); }
-
-  void Serialize(ResourceRequest& request) const override {
-    scoped_refptr<EncodedFormData> entity_body =
-        EncodedFormData::Create(data_.Utf8());
-    request.SetHttpBody(entity_body);
-    if (!data_.IsNull()) {
-      request.SetHTTPContentType(GetContentType());
-    }
-  }
-
-  const AtomicString GetContentType() const override {
-    return AtomicString("text/plain;charset=UTF-8");
-  }
-
- private:
-  const String data_;
-};
-
-class BeaconBlob final : public Beacon {
- public:
-  explicit BeaconBlob(Blob* data) : data_(data) {
-    const String& blob_type = data_->type();
-    if (!blob_type.IsEmpty() && ParsedContentType(blob_type).IsValid())
-      content_type_ = AtomicString(blob_type);
-  }
-
-  uint64_t size() const override { return data_->size(); }
-
-  void Serialize(ResourceRequest& request) const override {
-    DCHECK(data_);
-
-    scoped_refptr<EncodedFormData> entity_body = EncodedFormData::Create();
-    if (data_->HasBackingFile()) {
-      entity_body->AppendFile(To<File>(data_)->GetPath(),
-                              To<File>(data_)->LastModifiedTime());
-    } else {
-      entity_body->AppendBlob(data_->Uuid(), data_->GetBlobDataHandle());
-    }
-
-    request.SetHttpBody(std::move(entity_body));
-
-    if (!content_type_.IsEmpty()) {
-      if (!cors::IsCorsSafelistedContentType(content_type_)) {
-        request.SetMode(network::mojom::blink::RequestMode::kCors);
-      }
-      request.SetHTTPContentType(content_type_);
-    }
-  }
-
-  const AtomicString GetContentType() const override { return content_type_; }
-
- private:
-  Blob* const data_;
-  AtomicString content_type_;
-};
-
-class BeaconDOMArrayBufferView final : public Beacon {
- public:
-  explicit BeaconDOMArrayBufferView(DOMArrayBufferView* data) : data_(data) {
-    CHECK(base::CheckedNumeric<wtf_size_t>(data->byteLength()).IsValid())
-        << "EncodedFormData::Create cannot deal with huge ArrayBuffers.";
-  }
-
-  uint64_t size() const override { return data_->byteLength(); }
-
-  void Serialize(ResourceRequest& request) const override {
-    DCHECK(data_);
-
-    scoped_refptr<EncodedFormData> entity_body = EncodedFormData::Create(
-        data_->BaseAddress(),
-        base::checked_cast<wtf_size_t>(data_->byteLength()));
-    request.SetHttpBody(std::move(entity_body));
-  }
-
-  const AtomicString GetContentType() const override { return g_null_atom; }
-
- private:
-  DOMArrayBufferView* const data_;
-};
-
-class BeaconDOMArrayBuffer final : public Beacon {
- public:
-  explicit BeaconDOMArrayBuffer(DOMArrayBuffer* data) : data_(data) {
-    CHECK(base::CheckedNumeric<wtf_size_t>(data->ByteLength()).IsValid())
-        << "EncodedFormData::Create cannot deal with huge ArrayBuffers.";
-  }
-
-  uint64_t size() const override { return data_->ByteLength(); }
-
-  void Serialize(ResourceRequest& request) const override {
-    DCHECK(data_);
-
-    scoped_refptr<EncodedFormData> entity_body = EncodedFormData::Create(
-        data_->Data(), base::checked_cast<wtf_size_t>(data_->ByteLength()));
-    request.SetHttpBody(std::move(entity_body));
-  }
-
-  const AtomicString GetContentType() const override { return g_null_atom; }
-
- private:
-  DOMArrayBuffer* const data_;
-};
-
-class BeaconURLSearchParams final : public Beacon {
- public:
-  explicit BeaconURLSearchParams(URLSearchParams* data) : data_(data) {}
-
-  uint64_t size() const override {
-    return data_->toString().CharactersSizeInBytes();
-  }
-
-  void Serialize(ResourceRequest& request) const override {
-    DCHECK(data_);
-
-    request.SetHttpBody(data_->ToEncodedFormData());
-    request.SetHTTPContentType(GetContentType());
-  }
-
-  const AtomicString GetContentType() const override {
-    return AtomicString("application/x-www-form-urlencoded;charset=UTF-8");
-  }
-
- private:
-  URLSearchParams* const data_;
-};
-
-class BeaconFormData final : public Beacon {
- public:
-  explicit BeaconFormData(FormData* data)
-      : data_(data), entity_body_(data_->EncodeMultiPartFormData()) {
-    content_type_ = AtomicString("multipart/form-data; boundary=") +
-                    entity_body_->Boundary().data();
-  }
-
-  uint64_t size() const override { return entity_body_->SizeInBytes(); }
-
-  void Serialize(ResourceRequest& request) const override {
-    request.SetHttpBody(entity_body_.get());
-    request.SetHTTPContentType(content_type_);
-  }
-
-  const AtomicString GetContentType() const override { return content_type_; }
-
- private:
-  FormData* const data_;
-  scoped_refptr<EncodedFormData> entity_body_;
-  AtomicString content_type_;
-};
-
 bool SendBeaconCommon(const ScriptState& state,
                       LocalFrame* frame,
                       const KURL& url,
-                      const Beacon& beacon) {
+                      const BeaconData& beacon) {
   if (!frame->DomWindow()
            ->GetContentSecurityPolicyForWorld(&state.World())
            ->AllowConnectToSource(url, url, RedirectStatus::kNoRedirect)) {
diff --git a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context_test.cc b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context_test.cc
index 1529932..9c05cad 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context_test.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_inline_paint_context_test.cc
@@ -6,10 +6,19 @@
 
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
 
 namespace blink {
 
+namespace {
+
+String StringFromTextItem(const NGInlineCursor& cursor) {
+  return cursor.Current().Text(cursor).ToString().StripWhiteSpace();
+}
+
+}  // namespace
+
 class NGInlinePaintContextTest : public RenderingTest,
                                  private ScopedLayoutNGForTest,
                                  private ScopedTextDecoratingBoxForTest {
@@ -26,6 +35,70 @@
   }
 };
 
+TEST_F(NGInlinePaintContextTest, MultiLine) {
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    #container {
+      font-family: Ahem;
+      font-size: 10px;
+      line-height: 1;
+      margin: 0;
+      width: 800px;
+    }
+    .ul {
+      text-decoration-line: underline;
+    }
+    .no-cull {
+      background: yellow;
+    }
+    </style>
+    <div id="container" class="ul">
+      <br><br>
+      <span id="span" class="no-cull">
+        0<br>1
+      </span>
+    </div>
+  )HTML");
+  // Test the `#span` fragment in the first line.
+  const LayoutObject* span = GetLayoutObjectByElementId("span");
+  NGInlineCursor cursor;
+  cursor.MoveTo(*span);
+  ASSERT_TRUE(cursor.Current());
+  EXPECT_EQ(cursor.Current()->Type(), NGFragmentItem::kBox);
+  const NGFragmentItem& span0_item = *cursor.Current();
+  EXPECT_EQ(span0_item.InkOverflow(), PhysicalRect(0, 0, 10, 10));
+
+  // Test the text "0".
+  cursor.MoveToNext();
+  EXPECT_EQ(StringFromTextItem(cursor), "0");
+  const NGFragmentItem& text0_item = *cursor.Current();
+  EXPECT_EQ(text0_item.InkOverflow(), PhysicalRect(0, 0, 10, 10));
+
+  cursor.MoveToNext();
+  EXPECT_TRUE(cursor.Current().IsLineBreak());
+  const NGFragmentItem& br_item = *cursor.Current();
+  EXPECT_EQ(br_item.InkOverflow(), PhysicalRect(0, 0, 0, 10));
+
+  // Test the `#span` fragment in the second line.
+  cursor.MoveToNext();
+  EXPECT_EQ(cursor.Current()->Type(), NGFragmentItem::kLine);
+  cursor.MoveToNext();
+  EXPECT_EQ(cursor.Current()->Type(), NGFragmentItem::kBox);
+  const NGFragmentItem& span1_item = *cursor.Current();
+  EXPECT_EQ(span1_item.InkOverflow(), PhysicalRect(0, 0, 10, 10));
+
+  // Test the text "1".
+  cursor.MoveToNext();
+  EXPECT_EQ(StringFromTextItem(cursor), "1");
+  const NGFragmentItem& text1_item = *cursor.Current();
+  EXPECT_EQ(text1_item.InkOverflow(), PhysicalRect(0, 0, 10, 10));
+
+  // Test the containing block.
+  const NGPhysicalBoxFragment& container_fragment = cursor.ContainerFragment();
+  EXPECT_EQ(container_fragment.InkOverflow(), PhysicalRect(0, 0, 800, 40));
+}
+
 TEST_F(NGInlinePaintContextTest, VerticalAlign) {
   LoadAhem();
   SetBodyInnerHTML(R"HTML(
@@ -54,10 +127,6 @@
     </div>
   )HTML");
 
-  const auto StringFromTextItem = [](const NGInlineCursor& cursor) {
-    return cursor.Current().Text(cursor).ToString().StripWhiteSpace();
-  };
-
   NGInlineCursor cursor;
   const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
   cursor.MoveToIncludingCulledInline(*span1);
@@ -76,10 +145,14 @@
 
   // The bottom of ink overflows of `span1`, `span2`, and `span3` should match,
   // because underlines are drawn at the decorating box; i.e., `span1`.
-  EXPECT_EQ(span1_item.InkOverflow().Bottom(),
-            span2_item.InkOverflow().Bottom());
-  EXPECT_EQ(span1_item.InkOverflow().Bottom(),
-            span3_item.InkOverflow().Bottom());
+  EXPECT_EQ(span1_item.InkOverflow().Bottom() +
+                span1_item.OffsetInContainerFragment().top,
+            span2_item.InkOverflow().Bottom() +
+                span2_item.OffsetInContainerFragment().top);
+  EXPECT_EQ(span1_item.InkOverflow().Bottom() +
+                span1_item.OffsetInContainerFragment().top,
+            span3_item.InkOverflow().Bottom() +
+                span3_item.OffsetInContainerFragment().top);
 }
 
 TEST_F(NGInlinePaintContextTest, NestedBlocks) {
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc
index db1a6f7..59f02b8f 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
@@ -324,7 +325,10 @@
 
 void DedicatedWorker::DispatchErrorEventForScriptFetchFailure() {
   DCHECK(!GetExecutionContext() || GetExecutionContext()->IsContextThread());
-  // TODO(nhiroki): Add a console error message.
+  GetExecutionContext()->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+      mojom::blink::ConsoleMessageSource::kWorker,
+      mojom::blink::ConsoleMessageLevel::kError,
+      "new Worker() has failed to fetch script."));
   DispatchEvent(*Event::CreateCancelable(event_type_names::kError));
 }
 
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn
index 311f844b..50f10cd 100644
--- a/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -85,6 +85,8 @@
     "gpu_uncaptured_error_event.h",
     "gpu_validation_error.cc",
     "gpu_validation_error.h",
+    "string_utils.cc",
+    "string_utils.h",
     "texture_utils.cc",
     "texture_utils.h",
   ]
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index bb8a835..3df994a 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -196,8 +196,10 @@
     const GPUProgrammableStage* webgpu_stage) {
   DCHECK(webgpu_stage);
 
-  std::string entry_point = webgpu_stage->entryPoint().Ascii();
-  // length() is in bytes (not utf-8 characters or something), so this is ok.
+  std::string entry_point = webgpu_stage->entryPoint().Utf8();
+  // Compute the byte size of C-style null-terminated string for entry point
+  // name. length() is in bytes, and Non-ASCII codepoints are also considered as
+  // they are encoded as multiple bytes in UTF-8.
   size_t byte_size = entry_point.length() + 1;
 
   std::unique_ptr<char[]> entry_point_keepalive =
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index cbef3b03..4e1201f6 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_buffer.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_supported_features.h"
+#include "third_party/blink/renderer/modules/webgpu/string_utils.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_callback.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
@@ -109,7 +110,8 @@
   if (execution_context) {
     auto* console_message = MakeGarbageCollected<ConsoleMessage>(
         mojom::blink::ConsoleMessageSource::kRendering,
-        mojom::blink::ConsoleMessageLevel::kWarning, message);
+        mojom::blink::ConsoleMessageLevel::kWarning,
+        StringFromASCIIAndUTF8(message));
     execution_context->AddConsoleMessage(console_message);
   }
 }
@@ -218,7 +220,8 @@
     ExecutionContext* execution_context = ExecutionContext::From(script_state);
     auto* console_message = MakeGarbageCollected<ConsoleMessage>(
         mojom::blink::ConsoleMessageSource::kRendering,
-        mojom::blink::ConsoleMessageLevel::kWarning, error_message);
+        mojom::blink::ConsoleMessageLevel::kWarning,
+        StringFromASCIIAndUTF8(error_message));
     execution_context->AddConsoleMessage(console_message);
   }
   RecordAdapterForIdentifiability(script_state, options, gpu_adapter);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
index 2f30ad4..3234b5b 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_supported_features.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_supported_limits.h"
+#include "third_party/blink/renderer/modules/webgpu/string_utils.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 
 namespace blink {
@@ -112,7 +113,8 @@
   if (execution_context && allowed_console_warnings_remaining_ > 0) {
     auto* console_message = MakeGarbageCollected<ConsoleMessage>(
         mojom::blink::ConsoleMessageSource::kRendering,
-        mojom::blink::ConsoleMessageLevel::kWarning, message);
+        mojom::blink::ConsoleMessageLevel::kWarning,
+        StringFromASCIIAndUTF8(message));
     execution_context->AddConsoleMessage(console_message);
 
     allowed_console_warnings_remaining_--;
@@ -166,7 +168,8 @@
     case WGPURequestDeviceStatus_Unknown:
       DCHECK_EQ(dawn_device, nullptr);
       resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kOperationError, error_message));
+          DOMExceptionCode::kOperationError,
+          StringFromASCIIAndUTF8(error_message)));
       break;
     default:
       NOTREACHED();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.cc b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
index 3cae625..b418d680 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_texture.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_validation_error.h"
+#include "third_party/blink/renderer/modules/webgpu/string_utils.h"
 #include "third_party/blink/renderer/platform/bindings/microtask.h"
 
 namespace blink {
@@ -123,7 +124,8 @@
   if (execution_context && allowed_console_warnings_remaining_ > 0) {
     auto* console_message = MakeGarbageCollected<ConsoleMessage>(
         mojom::blink::ConsoleMessageSource::kRendering,
-        mojom::blink::ConsoleMessageLevel::kWarning, message);
+        mojom::blink::ConsoleMessageLevel::kWarning,
+        StringFromASCIIAndUTF8(message));
     execution_context->AddConsoleMessage(console_message);
 
     allowed_console_warnings_remaining_--;
@@ -245,9 +247,11 @@
 
   GPUUncapturedErrorEventInit* init = GPUUncapturedErrorEventInit::Create();
   if (errorType == WGPUErrorType_Validation) {
-    init->setError(MakeGarbageCollected<GPUValidationError>(message));
+    init->setError(MakeGarbageCollected<GPUValidationError>(
+        StringFromASCIIAndUTF8(message)));
   } else if (errorType == WGPUErrorType_OutOfMemory) {
-    init->setError(MakeGarbageCollected<GPUOutOfMemoryError>(message));
+    init->setError(MakeGarbageCollected<GPUOutOfMemoryError>(
+        StringFromASCIIAndUTF8(message)));
   } else {
     return;
   }
@@ -283,7 +287,8 @@
   ExecutionContext* execution_context = GetExecutionContext();
   if (execution_context) {
     auto* console_message = MakeGarbageCollected<ConsoleMessage>(
-        mojom::blink::ConsoleMessageSource::kRendering, level, message);
+        mojom::blink::ConsoleMessageSource::kRendering, level,
+        StringFromASCIIAndUTF8(message));
     execution_context->AddConsoleMessage(console_message);
   }
 }
@@ -295,8 +300,8 @@
   AddConsoleWarning(message);
 
   if (lost_property_->GetState() == LostProperty::kPending) {
-    auto* device_lost_info =
-        MakeGarbageCollected<GPUDeviceLostInfo>(reason, message);
+    auto* device_lost_info = MakeGarbageCollected<GPUDeviceLostInfo>(
+        reason, StringFromASCIIAndUTF8(message));
     lost_property_->Resolve(device_lost_info);
   }
 }
@@ -318,7 +323,7 @@
     case WGPUCreatePipelineAsyncStatus_DeviceDestroyed:
     case WGPUCreatePipelineAsyncStatus_Unknown: {
       resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kOperationError, message));
+          DOMExceptionCode::kOperationError, StringFromASCIIAndUTF8(message)));
       break;
     }
 
@@ -345,7 +350,7 @@
     case WGPUCreatePipelineAsyncStatus_DeviceDestroyed:
     case WGPUCreatePipelineAsyncStatus_Unknown: {
       resolver->Reject(MakeGarbageCollected<DOMException>(
-          DOMExceptionCode::kOperationError, message));
+          DOMExceptionCode::kOperationError, StringFromASCIIAndUTF8(message)));
       break;
     }
 
@@ -545,10 +550,12 @@
       resolver->Resolve(v8::Null(isolate));
       break;
     case WGPUErrorType_OutOfMemory:
-      resolver->Resolve(MakeGarbageCollected<GPUOutOfMemoryError>(message));
+      resolver->Resolve(MakeGarbageCollected<GPUOutOfMemoryError>(
+          StringFromASCIIAndUTF8(message)));
       break;
     case WGPUErrorType_Validation:
-      resolver->Resolve(MakeGarbageCollected<GPUValidationError>(message));
+      resolver->Resolve(MakeGarbageCollected<GPUValidationError>(
+          StringFromASCIIAndUTF8(message)));
       break;
     case WGPUErrorType_Unknown:
     case WGPUErrorType_DeviceLost:
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
index 15e9e49..5888744 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -222,7 +222,7 @@
   dawn_fragment->dawn_desc.nextInChain = nullptr;
   dawn_fragment->dawn_desc.module = descriptor->module()->GetHandle();
 
-  dawn_fragment->entry_point = descriptor->entryPoint().Ascii();
+  dawn_fragment->entry_point = descriptor->entryPoint().Utf8();
   dawn_fragment->dawn_desc.entryPoint = dawn_fragment->entry_point.c_str();
 
   // TODO(crbug.com/dawn/1041): implement pipeline overridable constants when
@@ -295,7 +295,7 @@
 
   dawn_vertex->module = vertex->module()->GetHandle();
 
-  dawn_desc_info->vertex_entry_point = vertex->entryPoint().Ascii();
+  dawn_desc_info->vertex_entry_point = vertex->entryPoint().Utf8();
   dawn_vertex->entryPoint = dawn_desc_info->vertex_entry_point.c_str();
 
   // TODO(crbug.com/dawn/1041): implement pipeline overridable constants when
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
index 2aedc42..b1791200 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.cc
@@ -14,6 +14,7 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_compilation_info.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_compilation_message.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+#include "third_party/blink/renderer/modules/webgpu/string_utils.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/webgpu_callback.h"
@@ -94,8 +95,8 @@
   for (uint32_t i = 0; i < info->messageCount; ++i) {
     const WGPUCompilationMessage* message = &info->messages[i];
     result->AppendMessage(MakeGarbageCollected<GPUCompilationMessage>(
-        message->message, message->type, message->lineNum, message->linePos,
-        message->offset, message->length));
+        StringFromASCIIAndUTF8(message->message), message->type,
+        message->lineNum, message->linePos, message->offset, message->length));
   }
 
   resolver->Resolve(result);
diff --git a/third_party/blink/renderer/modules/webgpu/string_utils.cc b/third_party/blink/renderer/modules/webgpu/string_utils.cc
new file mode 100644
index 0000000..dc996b6
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/string_utils.cc
@@ -0,0 +1,14 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/texture_utils.h"
+
+#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
+
+namespace blink {
+
+WTF::String StringFromASCIIAndUTF8(const char* message) {
+  return WTF::String::FromUTF8WithLatin1Fallback(message, strlen(message));
+}
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/string_utils.h b/third_party/blink/renderer/modules/webgpu/string_utils.h
new file mode 100644
index 0000000..68697edf7
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/string_utils.h
@@ -0,0 +1,23 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_STRING_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_STRING_UTILS_H_
+
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+// Create WTF::String from a null-terminated char string. Treat the provided
+// mesasge as UTF-8 string, with Latin1 as fallback if the string is not valid
+// UTF-8. Parts of Dawn's messages are user-defined strings like identifiers
+// that could possibly be invalid UTF8, and WTF::String::FromUTF8 would result
+// in a null string in this case. So use the FromUTF8WithLatin1Fallback methods
+// that fallbacks to Latin1 for invalid UTF8 strings so that we are always able
+// to display something.
+WTF::String StringFromASCIIAndUTF8(const char* message);
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_STRING_UTILS_H_
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9ddd517..e23d976 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1804,6 +1804,7 @@
 
 crbug.com/753671 [ Linux ] external/wpt/css/css-content/quotes-001.html [ Failure ]
 crbug.com/753671 [ Mac ] external/wpt/css/css-content/quotes-006.html [ Failure ]
+crbug.com/1341208 [ Mac ] external/wpt/css/css-content/quotes-007.html [ Skip ]
 crbug.com/753671 [ Mac ] external/wpt/css/css-content/quotes-009.html [ Failure ]
 crbug.com/753671 [ Mac10.13 ] external/wpt/css/css-content/quotes-012.html [ Failure ]
 crbug.com/753671 [ Mac10.14 ] external/wpt/css/css-content/quotes-012.html [ Failure ]
@@ -3359,6 +3360,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 [ Mac12 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-value-011.https.html [ Failure ]
 crbug.com/626703 [ Mac12 ] virtual/off-main-thread-css-paint/external/wpt/css/css-paint-api/registered-property-interpolation-001.https.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/hyphens/hyphenate-character-005.html [ Failure ]
 crbug.com/626703 [ Win10.20h2 ] wpt_internal/geolocation-api/watchPosition-page-visibility.https.html [ Timeout ]
@@ -5565,6 +5567,11 @@
 
 # V8 roll
 crbug.com/961059 fast/workers/worker-shared-asm-buffer.html [ Skip ]
+# For landing https://chromium-review.googlesource.com/c/v8/v8/+/3726147
+fast/js/kde/garbage-n.html [ Skip ]
+http/tests/devtools/console/console-worker-nested-imports-syntax-error.js [ Skip ]
+http/tests/workers/shared-worker-importScripts.html [ Skip ]
+http/tests/workers/worker-importScripts.html [ Skip ]
 
 # Temporarily disabled to unblock https://crrev.com/c/2979697
 crbug.com/1222114 http/tests/devtools/console/console-dir.js [ Failure Pass ]
diff --git a/third_party/blink/web_tests/android/WebviewWPTExpectations b/third_party/blink/web_tests/android/WebviewWPTExpectations
index 5e74f1c..707ab39 100644
--- a/third_party/blink/web_tests/android/WebviewWPTExpectations
+++ b/third_party/blink/web_tests/android/WebviewWPTExpectations
@@ -4977,14 +4977,12 @@
 crbug.com/1050754 external/wpt/webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/no-cors.https.html [ Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-badargs-authnrselection.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-badargs-challenge.https.html [ Crash Failure ]
-crbug.com/1050754 external/wpt/webauthn/createcredential-badargs-rp.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-badargs-user.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-excludecredentials.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-extensions.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-getpublickey.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-large-blob-not-supported.https.html [ Crash ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-large-blob-supported.https.html [ Crash ]
-crbug.com/1050754 external/wpt/webauthn/createcredential-passing.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-pubkeycredparams.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/createcredential-timeout.https.html [ Crash Failure ]
 crbug.com/1050754 external/wpt/webauthn/getcredential-badargs-rpid.https.html [ Crash Failure ]
diff --git a/third_party/blink/web_tests/external/Version b/third_party/blink/web_tests/external/Version
index 3831a25..aabada20 100644
--- a/third_party/blink/web_tests/external/Version
+++ b/third_party/blink/web_tests/external/Version
@@ -1 +1 @@
-Version: f1c5bcd1613a7d7d35d07b3edc4e4aef7fc815d1
+Version: 6ac81d105d601a47ab9f89d6b9985f91a4c9ad8a
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 6171773..493d177 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
@@ -82053,6 +82053,19 @@
         {}
        ]
       ],
+      "multi-line-column-flex-fragmentation-050.html": [
+       "b0467d5b80501113d638d3262f994a9b95e13020",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "multi-line-row-flex-fragmentation-001.html": [
        "ba6b0103e447994a2778cbd9ea356a490f62b8fb",
        [
@@ -82833,6 +82846,32 @@
         {}
        ]
       ],
+      "multi-line-row-flex-fragmentation-061.html": [
+       "10f8a666e4f12636cad0b42c7032be185b1b9371",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "multi-line-row-flex-fragmentation-062.html": [
+       "1d9d8739a9147c084a5a8ad814a85ad05a553888",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "single-line-column-flex-fragmentation-001.html": [
        "d1411f9a16a14585b945408b162182ed343419d2",
        [
@@ -83548,6 +83587,45 @@
         {}
        ]
       ],
+      "single-line-column-flex-fragmentation-056.html": [
+       "87091a423a11466de8a1131067e890fd2a1cae48",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "single-line-column-flex-fragmentation-057.html": [
+       "9261477e7dc3551c27453eda8c527dea5746925d",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "single-line-column-flex-fragmentation-058.html": [
+       "ec00e47436b6fea0cd368d395089d6b9327641eb",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "single-line-row-flex-fragmentation-001.html": [
        "379327a4aff584192f076d3f9d8f3ead232c0f5c",
        [
@@ -84028,6 +84106,58 @@
         ],
         {}
        ]
+      ],
+      "single-line-row-flex-fragmentation-038.html": [
+       "d9ea2acc4c1451435b4e5ac33f93f5bfcf6c9bae",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "single-line-row-flex-fragmentation-039.html": [
+       "5c3a039d47357425d3d5b1722bcdc70e03d3858c",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "single-line-row-flex-fragmentation-040.html": [
+       "90d86129640d020e99baf35a10f5aa0b80c87e83",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "single-line-row-flex-fragmentation-041.html": [
+       "112e963a2258aa23427dec54c5e99c20d5cf417c",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
       ]
      },
      "float-000.html": [
@@ -87036,6 +87166,58 @@
         {}
        ]
       ],
+      "caption-margin-001.html": [
+       "cb2746ef1580e72c110b53c8e5fc7b3160b2e9bb",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "caption-margin-002.html": [
+       "3bb06bde1dc30cf89594e7f8a3642bf14b72ce5c",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "caption-margin-003.html": [
+       "e591c9e058ef34fad2afd7d0fa684356d1234b72",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
+      "caption-margin-004.html": [
+       "5c70c70728c80f73fc49c69e289a0588a887fd30",
+       [
+        null,
+        [
+         [
+          "/css/reference/ref-filled-green-100px-square.xht",
+          "=="
+         ]
+        ],
+        {}
+       ]
+      ],
       "repeated-section": {
        "abspos-in-monolithic.tentative.html": [
         "6ec70d030d233a8183bbf281503235e2cb005b66",
@@ -245313,7 +245495,7 @@
     "timing-model": {
      "animations": {
       "document-timeline-animation.html": [
-       "5fbfd2acfdd2f1961e8a966ad651ea31762407da",
+       "7d4dc768498608bfd32bf00f71aca57925e6719f",
        [
         null,
         [
@@ -253118,7 +253300,7 @@
       []
      ],
      "prefetch-helper.js": [
-      "4beae888593395c4cfdc4d1d1fcbc920f1233edd",
+      "cb6fd4823f008f940bb1c292a3ef504194856df6",
       []
      ],
      "prefetch-subresource.css": [
@@ -265117,7 +265299,7 @@
        []
       ],
       "quotes-034-ref.html": [
-       "7ec4cd8e3690cabd531bc4fde5f9549e46ba8340",
+       "bfe7163f13276f181c2aeb765f20dad74c0cf204",
        []
       ]
      },
@@ -288954,7 +289136,7 @@
      "parsing": {
       "support": {
        "toggle-root-values.js": [
-        "85239db0ffb3dc386ef83e42ac59510c9686ce30",
+        "0bedfb9dfe06308600ecda1925381d0343668f1b",
         []
        ]
       }
@@ -321200,11 +321382,11 @@
       []
      ],
      "mediasource-worker-detach-element.js": [
-      "10c2f84db89c2a16985e5d65c18232bfc238b0d9",
+      "3007f6ed983fa4153b6f7b7ee76268cb3bb08cc8",
       []
      ],
      "mediasource-worker-duration.js": [
-      "e4901345fc4da09ebf16fb6b74504a100491398d",
+      "d868fc4a1fecfdf1357991aa5b3862c0354b93cc",
       []
      ],
      "mediasource-worker-get-objecturl.js": [
@@ -321228,7 +321410,7 @@
       []
      ],
      "mediasource-worker-play.js": [
-      "e29b1b8de6397b98f95b8241676274d06be0a633",
+      "d2f3aa031cd9bc00054584ed803352bc8c17bdda",
       []
      ],
      "mediasource-worker-util.js": [
@@ -325824,7 +326006,7 @@
       []
      ],
      "entry-invariants.js": [
-      "0bb18c5983341b25c72f3418e5e167fcf4053be6",
+      "4bef9496103ca61475f8041a7d2c57b2b5d9fc4e",
       []
      ],
      "eventsource.py": [
@@ -333293,7 +333475,7 @@
      []
     ],
     "helpers.js": [
-     "27a5613022102cf1bf561159de8fd63d0e1016c8",
+     "4fb1904b45340efe1f9efdee1c3a236689f7fa4f",
      []
     ],
     "remote-desktop-client-override.tentative.https.html.ini": [
@@ -333302,7 +333484,7 @@
     ],
     "resources": {
      "common-inputs.js": [
-      "8370f7f079a014ea58dd3ce606b7fa48dcc88a3e",
+      "6fa0005f60fa21a6a12886e188f4d4b197305e98",
       []
      ],
      "utils.js": [
@@ -373976,7 +374158,7 @@
       ]
      ],
      "system-color-compute.html": [
-      "fffc368f4eb75dbeb741d0426dcd65d634493349",
+      "ed4f3b947e81b91e0a63a5f8be619586be89e73c",
       [
        null,
        {}
@@ -374196,7 +374378,7 @@
        ]
       ],
       "at-container-parsing.html": [
-       "5b2ed7f31c9b5ce1772da15ca25f6dde858efe6b",
+       "6278f88216f314bb4a63a4826cfd8dacc5fc349e",
        [
         null,
         {}
@@ -374266,7 +374448,7 @@
        ]
       ],
       "container-computed.html": [
-       "b38b0d83dbe361db58855f5d9894eb60ef19e31e",
+       "d83f3616400518bcceeb567678211b454eb95324",
        [
         null,
         {}
@@ -374280,7 +374462,7 @@
        ]
       ],
       "container-inheritance.html": [
-       "efc09983c0ddc97c393351633b7bf680f5ed4aae",
+       "b333b691fd78789af20d15b235cf1a88c0e91f5c",
        [
         null,
         {}
@@ -374315,7 +374497,7 @@
        ]
       ],
       "container-name-parsing.html": [
-       "b253ee8573fe29ccc5a6934fc0b98b58652b9a92",
+       "217a73fb68cb60ac9f29a22d38a54ab3fe1c7e9d",
        [
         null,
         {}
@@ -374329,7 +374511,7 @@
        ]
       ],
       "container-parsing.html": [
-       "b8ac6929671536a1266393ef8514528e2ea9765e",
+       "9f1293f51cc7dfc1e22b12f7a8b16feb90e40693",
        [
         null,
         {}
@@ -374364,7 +374546,7 @@
        ]
       ],
       "container-type-computed.html": [
-       "cd5f1cbb789e2eee7c8cb239b7285d04e04f6823",
+       "0b5e033a0f302e904414447e2a7eb9be8eadfb39",
        [
         null,
         {}
@@ -374392,7 +374574,7 @@
        ]
       ],
       "container-type-parsing.html": [
-       "cce8aa3b90630da9b2dcac6bb7911172fd1deeb3",
+       "34023cbc4f2ad022b10f1b6d311f4a2163a33810",
        [
         null,
         {}
@@ -374441,7 +374623,7 @@
        ]
       ],
       "container-units-invalidation.html": [
-       "0cb5b15f4a8e3666a5fbf60542e65fe6a5c31da8",
+       "1bc708dc88b0c20a406d5b779a12d0a43e5db747",
        [
         null,
         {}
@@ -386310,6 +386492,13 @@
         {}
        ]
       ],
+      "changing-scroll-snap-type-on-root-element.html": [
+       "c86f39b9d6cc3c2ebf896aca2a59fec707bd979e",
+       [
+        null,
+        {}
+       ]
+      ],
       "changing-scroll-snap-type.html": [
        "70774b3d40f691fe4feb623b4dfe430b12f4e8c0",
        [
@@ -391613,14 +391802,14 @@
        ]
       ],
       "toggle-root-interpolation.tentative.html": [
-       "5cc3257526adeb737fc654ca21cf6c575e1f05b1",
+       "855b7e6551cc7b38eea1e8683a43e21874d8f611",
        [
         null,
         {}
        ]
       ],
       "toggle-trigger-interpolation.tentative.html": [
-       "1ea9e652eaf270509ef9ca73e66233c7eed074ec",
+       "1ebec55ef0dd998584bc620423b6b9d0d49f8e0d",
        [
         null,
         {}
@@ -391685,21 +391874,21 @@
        ]
       ],
       "toggle-trigger-computed.tentative.html": [
-       "571cac91f0224e15c141f32c9c513e41ff6ade68",
+       "4dab2b604545f1826a4e9d07bc8edd757559cad4",
        [
         null,
         {}
        ]
       ],
       "toggle-trigger-invalid.tentative.html": [
-       "333cfbaa2e6bca12dc6381bd0b355d87a7a437a0",
+       "584c4986f7a5b278993d2cba6233436b0aa5fa11",
        [
         null,
         {}
        ]
       ],
       "toggle-trigger-valid.tentative.html": [
-       "d64b3cd43b9b5e4a953585717a7f607dd8938c6f",
+       "1b4a896f20ecc96e79eff65a11021b0ed4de0864",
        [
         null,
         {}
@@ -391714,7 +391903,7 @@
       ]
      },
      "toggle-shorthand-serialization.tentative.html": [
-      "e98a481964176b7cab02a17c4f6aa93d8792bf2b",
+      "682945c2e2bf930f8cbba606a1c7e7be37d6e7a4",
       [
        null,
        {}
@@ -394064,7 +394253,7 @@
         ]
        ],
        "container-type.html": [
-        "d52915492390dc0c6300a710f7f77565c7754145",
+        "c823ffb759894f1a1cbc2a2f095eca9210ba9c84",
         [
          null,
          {}
@@ -398339,6 +398528,13 @@
        {}
       ]
      ],
+     "checkVisibility.html": [
+      "293604ef2650a05bcb27a078102e9b4e4ccaf733",
+      [
+       null,
+       {}
+      ]
+     ],
      "client-props-inline-list-item.html": [
       "725bb787a5e65b8dc635ffa5e249144ba3ac7ee4",
       [
@@ -398754,13 +398950,6 @@
        {}
       ]
      ],
-     "isVisible.html": [
-      "0679a75647e7fd10432477a3a58bdead140099ec",
-      [
-       null,
-       {}
-      ]
-     ],
      "matchMedia-display-none-iframe.html": [
       "08fcb3c5386228b167cc76e9cd02a34903c86912",
       [
@@ -491008,14 +491197,14 @@
      ]
     ],
     "MediaStreamTrack-applyConstraints-fast.html": [
-     "5c5d3e119b77bd68cf90698bc89b943de92639d9",
+     "2bc5999544f7c351e172e13aa45fba818f8e80c5",
      [
       null,
       {}
      ]
     ],
     "MediaStreamTrack-applyConstraints-getSettings.https.html": [
-     "ea45438536510371a90f16a0da4577a43eb75cbb",
+     "3b52dd56936a4d09987f4efc16e63d477d2ac17d",
      [
       null,
       {
@@ -491024,7 +491213,7 @@
      ]
     ],
     "MediaStreamTrack-applyConstraints-reject.https.html": [
-     "395ef17ca8bb264191c1618669f9b6e4606cae26",
+     "2935327368d8ab983fdec9b0120fa5c435d94177",
      [
       null,
       {
@@ -499060,6 +499249,24 @@
        null,
        {}
       ]
+     ],
+     "requestPermission.https.window.js": [
+      "2c96d26d10f42c1aba6156a49beb595e270b8618",
+      [
+       "orientation-event/motion/requestPermission.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "script",
+          "/resources/testdriver.js"
+         ],
+         [
+          "script",
+          "/resources/testdriver-vendor.js"
+         ]
+        ]
+       }
+      ]
      ]
     },
     "orientation": {
@@ -499140,6 +499347,24 @@
        {}
       ]
      ],
+     "requestPermission.https.window.js": [
+      "4a39a238d018d20e5c3f968d6cd5fc68cd0ce8ca",
+      [
+       "orientation-event/orientation/requestPermission.https.window.html",
+       {
+        "script_metadata": [
+         [
+          "script",
+          "/resources/testdriver.js"
+         ],
+         [
+          "script",
+          "/resources/testdriver-vendor.js"
+         ]
+        ]
+       }
+      ]
+     ],
      "updates.https.html": [
       "c84588d5985d4a327ce164826fd915bf54a52a8b",
       [
@@ -516679,7 +516904,7 @@
      ]
     ],
     "entries-for-network-errors.sub.https.html": [
-     "a3c4791f68d9a187cc807c250da387945eee06ad",
+     "95849d282621ffc121ae36a3f3543307a4e135db",
      [
       null,
       {}
@@ -546842,7 +547067,7 @@
      ]
     ],
     "createcredential-badargs-rp.https.html": [
-     "6ddd715306d119b0864ea0b57d16205c137595ac",
+     "5e3c38821bc3946a58a080d471c23fe369b2e870",
      [
       null,
       {
@@ -546922,7 +547147,7 @@
      ]
     ],
     "createcredential-passing.https.html": [
-     "2c744b25585552188253720882e919718ac5c1a3",
+     "f64a4ff0397222b21379265591a2f09a9b906c97",
      [
       null,
       {
@@ -567937,6 +568162,13 @@
        {}
       ]
      ],
+     "ar_hittest_subscription_unlocalizable.https.html": [
+      "d1cb1a5a5c44404e5666fe8f7ba1f9cd66694a7e",
+      [
+       null,
+       {}
+      ]
+     ],
      "idlharness.https.html": [
       "f61959b9edab6c6d561bbff90f2dc0d2a66e91b2",
       [
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type-on-root-element.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type-on-root-element.html
new file mode 100644
index 0000000..c86f39b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-after-relayout/changing-scroll-snap-type-on-root-element.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<html>
+<title>
+  Updating the scroll-snap-type of the root element should make it resnap accordingly.
+  This is another vairant of changing-scroll-snap-type.html for the root element.
+</title>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap/#re-snap" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  position: absolute;
+  margin: 0;
+}
+
+html {
+  overflow: hidden;
+  scroll-snap-type: none;
+}
+
+#y-target {
+  width: 300px;
+  height: 300px;
+  top: 100px;
+  left: 0;
+  background-color: green;
+  scroll-snap-align: start none;
+}
+
+#x-target {
+  width: 300px;
+  height: 300px;
+  top: 0;
+  left: 100px;
+  background-color: red;
+  scroll-snap-align: none start;
+}
+
+.area {
+  width: 1000vw;
+  height: 1000vh;
+}
+</style>
+
+<div class="area"></div>
+<div id="x-target"></div>
+<div id="y-target"></div>
+
+<script>
+const x_target = document.getElementById("x_target");
+const y_target = document.getElementById("y_target");
+const scroller = document.documentElement;
+
+function cleanup() {
+  scroller.style.setProperty("scroll-snap-type", "none");
+}
+
+test(t => {
+  t.add_cleanup(cleanup);
+  scroller.scrollTo(0,0);
+  assert_equals(scroller.scrollTop, 0);
+  assert_equals(scroller.scrollLeft, 0);
+
+  scroller.style.setProperty("scroll-snap-type", "y mandatory");
+  assert_equals(scroller.scrollTop, 100);
+  assert_equals(scroller.scrollLeft, 0);
+}, "Changing the scroller's snap type to y should make it resnap on the y-axis.");
+
+test(t => {
+  t.add_cleanup(cleanup);
+  scroller.scrollTo(0,0);
+  assert_equals(scroller.scrollTop, 0);
+  assert_equals(scroller.scrollLeft, 0);
+
+  scroller.style.setProperty("scroll-snap-type", "x mandatory");
+  assert_equals(scroller.scrollLeft, 100);
+  assert_equals(scroller.scrollTop, 0);
+}, "Changing the scroller's snap type to x should make it resnap on the x-axis.");
+
+
+test(t => {
+  t.add_cleanup(cleanup);
+  scroller.scrollTo(0,0);
+  assert_equals(scroller.scrollTop, 0);
+  assert_equals(scroller.scrollLeft, 0);
+
+  scroller.style.setProperty("scroll-snap-type", "x mandatory");
+  assert_equals(scroller.scrollLeft, 100);
+  assert_equals(scroller.scrollTop, 0);
+
+  scroller.style.setProperty("scroll-snap-type", "y mandatory");
+  assert_equals(scroller.scrollTop, 100);
+}, "Changing the scroller's snap type axis should make it resnap.");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https.html b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https.html
index 6ddd715..5e3c388 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https.html
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-badargs-rp.https.html
@@ -35,10 +35,6 @@
 
     // // rp.name
     new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", TypeError);
-
-    // rp.icon
-    new CreateCredentialsTest("options.publicKey.rp.icon", "http://fidoalliance.co.nz/testimages/catimage.png")
-      .runTest("Bad rp: icon is insecure", "SecurityError");
 });
 
 /* JSHINT */
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https.html b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https.html
index 2c744b2..f64a4ff 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https.html
+++ b/third_party/blink/web_tests/external/wpt/webauthn/createcredential-passing.https.html
@@ -21,7 +21,6 @@
 
     // rp
     new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.hostname}).runTest("passing credentials.create() with rpId (hostname)");
-    new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).runTest("passing credentials.create() without rp.icon");
 
     // user
     new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(1)).runTest("very short user id");
@@ -33,7 +32,6 @@
     new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(16)).runTest("Float32Array user id");
     var dvBuf1 = new ArrayBuffer(16);
     new CreateCredentialsTest("options.publicKey.user.id", new DataView(dvBuf1)).runTest("DataView user id");
-    new CreateCredentialsTest({path: "options.publicKey.user.icon", value: undefined}).runTest("passing credentials.create() without user.icon");
 
     // good challenge values
     // all these challenges are zero-filled buffers... think anyone will complain?
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/helpers.js b/third_party/blink/web_tests/external/wpt/webauthn/helpers.js
index 27a5613..4fb1904b 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/helpers.js
+++ b/third_party/blink/web_tests/external/wpt/webauthn/helpers.js
@@ -19,7 +19,6 @@
             // Relying Party:
             rp: {
                 name: "Acme",
-                icon: "https://www.w3.org/StyleSheets/TR/2016/logos/W3C"
             },
 
             // User:
@@ -27,7 +26,6 @@
                 id: new Uint8Array(16), // Won't survive the copy, must be rebuilt
                 name: "john.p.smith@example.com",
                 displayName: "John P. Smith",
-                icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
             },
 
             pubKeyCredParams: [{
diff --git a/third_party/blink/web_tests/external/wpt/webauthn/resources/common-inputs.js b/third_party/blink/web_tests/external/wpt/webauthn/resources/common-inputs.js
index 8370f7f0..6fa0005 100644
--- a/third_party/blink/web_tests/external/wpt/webauthn/resources/common-inputs.js
+++ b/third_party/blink/web_tests/external/wpt/webauthn/resources/common-inputs.js
@@ -10,7 +10,6 @@
     id: new TextEncoder().encode("123456789"),
     name: "madeline@example.com",
     displayName: "Madeline",
-    icon: "https://example.com/celeste.png"
 };
 
 // ES256.
diff --git a/third_party/blink/web_tests/platform/generic/fast/js/instanceof-test-expected.txt b/third_party/blink/web_tests/platform/generic/fast/js/instanceof-test-expected.txt
index 8cc2845..56750df0 100644
--- a/third_party/blink/web_tests/platform/generic/fast/js/instanceof-test-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/fast/js/instanceof-test-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: new Worker() has failed to fetch script.
 instanceof test
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/blink/web_tests/platform/generic/fast/workers/chromium/worker-finish-crash-expected.txt b/third_party/blink/web_tests/platform/generic/fast/workers/chromium/worker-finish-crash-expected.txt
index 654cd1b8..f1b79f73 100644
--- a/third_party/blink/web_tests/platform/generic/fast/workers/chromium/worker-finish-crash-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/fast/workers/chromium/worker-finish-crash-expected.txt
@@ -1 +1,2 @@
+CONSOLE ERROR: new Worker() has failed to fetch script.
 Test to ensure that finishing a Worker won't re-enter. We pass if we don't crash.
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-invalid-context-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-invalid-context-expected.txt
index 9edcdd3..9f12b4cf 100644
--- a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-invalid-context-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-invalid-context-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: new Worker() has failed to fetch script.
 This test checks that the invalid context doesn't cause crashes.
 
 DONE
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-redirect-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-redirect-expected.txt
index 3120832..7986e3c 100644
--- a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-redirect-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-redirect-expected.txt
@@ -1,5 +1,6 @@
 CONSOLE ERROR: Unsafe attempt to load URL http://localhost:8000/workers/resources/worker-redirect-target.js from frame with URL http://127.0.0.1:8000/workers/worker-redirect.html. Domains, protocols and ports must match.
 
+CONSOLE ERROR: new Worker() has failed to fetch script.
 Test that loading the worker's script does not allow a cross origin redirect (bug 26146)
 
 SUCCESS: threw exception (SecurityError: Failed to construct 'Worker': Script at 'http://localhost:8000/workers/resources/worker-target.js' cannot be accessed from origin 'http://127.0.0.1:8000'.) when attempting to cross origin while loading the worker script.
diff --git a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-workerScriptNotThere-expected.txt b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-workerScriptNotThere-expected.txt
index 806443e..bd7c97d 100644
--- a/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-workerScriptNotThere-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/http/tests/workers/worker-workerScriptNotThere-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: new Worker() has failed to fetch script.
 Test worker file does not exist error. Should print two "PASS" statements followed by "DONE".
 
 The order of the error events should be onerror and then error event, and this test should be improved to verify that when bug https://bugs.webkit.org/show_bug.cgi?id=62485 is fixed.
diff --git a/third_party/blink/web_tests/platform/generic/virtual/plz-dedicated-worker/http/tests/workers/worker-redirect-expected.txt b/third_party/blink/web_tests/platform/generic/virtual/plz-dedicated-worker/http/tests/workers/worker-redirect-expected.txt
index cd233a3..24e804a 100644
--- a/third_party/blink/web_tests/platform/generic/virtual/plz-dedicated-worker/http/tests/workers/worker-redirect-expected.txt
+++ b/third_party/blink/web_tests/platform/generic/virtual/plz-dedicated-worker/http/tests/workers/worker-redirect-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE ERROR: new Worker() has failed to fetch script.
 Test that loading the worker's script does not allow a cross origin redirect (bug 26146)
 
 SUCCESS: threw exception (SecurityError: Failed to construct 'Worker': Script at 'http://localhost:8000/workers/resources/worker-target.js' cannot be accessed from origin 'http://127.0.0.1:8000'.) when attempting to cross origin while loading the worker script.
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index 86e62ea..82f8499 100644
--- a/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -6,8 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [208, 988, 173, 19],
-        [427, 988, 150, 19],
+        [208, 988, 173, 18],
+        [427, 988, 150, 18],
         [382, 985, 45, 24],
         [423, 988, 5, 18],
         [380, 988, 5, 18]
diff --git a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index 86e62ea..82f8499 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/blink/web_tests/platform/linux/virtual/backface-visibility-interop/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -6,8 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [208, 988, 173, 19],
-        [427, 988, 150, 19],
+        [208, 988, 173, 18],
+        [427, 988, 150, 18],
         [382, 985, 45, 24],
         [423, 988, 5, 18],
         [380, 988, 5, 18]
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index a886e441..e37aac0 100644
--- a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -6,8 +6,8 @@
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
       "invalidations": [
-        [177, 1029, 202, 19],
-        [435, 1029, 173, 19],
+        [177, 1029, 202, 18],
+        [435, 1029, 173, 18],
         [382, 1026, 50, 24],
         [429, 1029, 6, 18],
         [379, 1029, 6, 18]
diff --git a/third_party/protobuf/patches/0031-workaround-cfi-unrelated-cast.patch b/third_party/protobuf/patches/0031-workaround-cfi-unrelated-cast.patch
index e15da35..9f7f337 100644
--- a/third_party/protobuf/patches/0031-workaround-cfi-unrelated-cast.patch
+++ b/third_party/protobuf/patches/0031-workaround-cfi-unrelated-cast.patch
@@ -1,5 +1,5 @@
 diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
-index 0524fd46226e6..6fb9e74685e6b 100644
+index 0524fd46226e6..082e5124a023f 100644
 --- a/src/google/protobuf/descriptor.cc
 +++ b/src/google/protobuf/descriptor.cc
 @@ -301,22 +301,16 @@ class FlatAllocation {
@@ -11,7 +11,7 @@
 -  // that is not yet initialized to be of that type.
 -  // (from -fsanitize=cfi-unrelated-cast)
    template <typename U>
-+  __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
++  PROTOBUF_NO_SANITIZE("cfi-unrelated-cast", "vptr")
    U* Begin() const {
 -    int begin = BeginOffset<U>(), end = EndOffset<U>();
 -    if (begin == end) return nullptr;
@@ -20,7 +20,7 @@
    }
  
    template <typename U>
-+  __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
++  PROTOBUF_NO_SANITIZE("cfi-unrelated-cast", "vptr")
    U* End() const {
 -    int begin = BeginOffset<U>(), end = EndOffset<U>();
 -    if (begin == end) return nullptr;
@@ -29,3 +29,20 @@
    }
  
    template <typename U>
+diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
+index cae9ebe01ec2c..b84b55e4d8762 100644
+--- a/src/google/protobuf/port_def.inc
++++ b/src/google/protobuf/port_def.inc
+@@ -764,6 +764,12 @@
+ #define PROTOBUF_UNUSED
+ #endif
+ 
++#if __has_attribute(no_sanitize)
++#define PROTOBUF_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__)))
++#else
++#define PROTOBUF_NO_SANITIZE
++#endif
++
+ // ThreadSafeArenaz is turned off completely in opensource builds.
+ 
+ // Windows declares several inconvenient macro names.  We #undef them and then
diff --git a/third_party/protobuf/src/google/protobuf/descriptor.cc b/third_party/protobuf/src/google/protobuf/descriptor.cc
index 6fb9e74..082e512 100644
--- a/third_party/protobuf/src/google/protobuf/descriptor.cc
+++ b/third_party/protobuf/src/google/protobuf/descriptor.cc
@@ -302,13 +302,13 @@
   }
 
   template <typename U>
-  __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
+  PROTOBUF_NO_SANITIZE("cfi-unrelated-cast", "vptr")
   U* Begin() const {
     return reinterpret_cast<U*>(data() + BeginOffset<U>());
   }
 
   template <typename U>
-  __attribute__((no_sanitize("cfi-unrelated-cast", "vptr")))
+  PROTOBUF_NO_SANITIZE("cfi-unrelated-cast", "vptr")
   U* End() const {
     return reinterpret_cast<U*>(data() + EndOffset<U>());
   }
diff --git a/third_party/protobuf/src/google/protobuf/port_def.inc b/third_party/protobuf/src/google/protobuf/port_def.inc
index cae9ebe0..684b700 100644
--- a/third_party/protobuf/src/google/protobuf/port_def.inc
+++ b/third_party/protobuf/src/google/protobuf/port_def.inc
@@ -764,6 +764,12 @@
 #define PROTOBUF_UNUSED
 #endif
 
+#if __has_attribute(no_sanitize)
+#define PROTOBUF_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__)))
+#else
+#define PROTOBUF_NO_SANITIZE
+#endif
+
 // ThreadSafeArenaz is turned off completely in opensource builds.
 
 // Windows declares several inconvenient macro names.  We #undef them and then
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 91ca7e5e..d5eec97 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -32628,7 +32628,7 @@
   <int value="21" label="APP_WINDOW_ON_RESTORED"/>
   <int value="22" label="DELETED_AUDIO_MODEM_ON_RECEIVED"/>
   <int value="23" label="DELETED_AUDIO_MODEM_ON_TRANSMIT_FAIL"/>
-  <int value="24" label="AUDIO_ON_DEVICE_CHANGED"/>
+  <int value="24" label="DELETED_AUDIO_ON_DEVICE_CHANGED"/>
   <int value="25" label="AUDIO_ON_DEVICES_CHANGED"/>
   <int value="26" label="AUDIO_ON_LEVEL_CHANGED"/>
   <int value="27" label="AUDIO_ON_MUTE_CHANGED"/>
@@ -33127,7 +33127,7 @@
   <int value="492" label="LOGIN_ON_REQUEST_EXTERNAL_LOGOUT"/>
   <int value="493" label="LOGIN_ON_EXTERNAL_LOGOUT_DONE"/>
   <int value="494" label="ACCESSIBILITY_PRIVATE_ON_PUMPKIN_INSTALLED"/>
-  <int value="495" label="REMOTE_APPS_ON_REMOTE_APP_LAUNCHED"/>
+  <int value="495" label="ENTERPRISE_REMOTE_APPS_ON_REMOTE_APP_LAUNCHED"/>
   <int value="496" label="INPUT_METHOD_PRIVATE_ON_CARET_BOUNDS_CHANGED"/>
 </enum>
 
@@ -33609,7 +33609,7 @@
   <int value="454" label="DELETED_BLUETOOTH_REMOVEPROFILE"/>
   <int value="455" label="DELETED_BLUETOOTH_GETPROFILES"/>
   <int value="456" label="EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN"/>
-  <int value="457" label="AUDIO_GETINFO"/>
+  <int value="457" label="DELETED_AUDIO_GETINFO"/>
   <int value="458" label="AUDIO_SETACTIVEDEVICES"/>
   <int value="459" label="AUDIO_SETPROPERTIES"/>
   <int value="460" label="USB_RESETDEVICE"/>
@@ -34884,6 +34884,7 @@
   <int value="1675" label="DEVELOPERPRIVATE_GETUSERANDEXTENSIONSITESBYETLD"/>
   <int value="1676" label="AUTOTESTPRIVATE_SENDARCOVERLAYCOLOR"/>
   <int value="1677" label="AUTOTESTPRIVATE_ISINPUTMETHODREADYFORTESTING"/>
+  <int value="1678" label="AUTOTESTPRIVATE_GETARCAPPKILLS"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -57677,6 +57678,7 @@
   <int value="-479601398" label="InfoCardAcknowledgementTracking:enabled"/>
   <int value="-478462945" label="enable-ephemeral-apps"/>
   <int value="-477101783" label="HandwritingGesture:disabled"/>
+  <int value="-476171840" label="EnableFamilyInfoFeedback:enabled"/>
   <int value="-475049740" label="disable-vr-shell"/>
   <int value="-475042780" label="DialMediaRouteProvider:enabled"/>
   <int value="-474833105" label="CrostiniUseBusterImage:enabled"/>
@@ -58186,6 +58188,7 @@
       label="AutofillEnableManualFallbackForVirtualCards:enabled"/>
   <int value="-128687277"
       label="OmniboxUIExperimentHideSteadyStateUrlPathQueryAndRef:disabled"/>
+  <int value="-128289378" label="EnableFamilyInfoFeedback:disabled"/>
   <int value="-127666141" label="TabGroups:disabled"/>
   <int value="-127231994" label="VrBrowsingNativeAndroidUi:disabled"/>
   <int value="-125941743" label="EnableLogControllerForDiagnosticsApp:enabled"/>
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index f548c98..d43537c 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -4246,7 +4246,7 @@
 </histogram>
 
 <histogram name="Android.WebView.OnRenderProcessGoneResult"
-    enum="AndroidWebViewRenderProcessGoneResult" expires_after="2022-08-03">
+    enum="AndroidWebViewRenderProcessGoneResult" expires_after="2023-06-30">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
@@ -4542,7 +4542,7 @@
 </histogram>
 
 <histogram name="Android.WebView.TargetSdkVersion" enum="AndroidApiLevel"
-    expires_after="2022-07-21">
+    expires_after="2023-06-30">
   <owner>ntfschr@chromium.org</owner>
   <owner>src/android_webview/OWNERS</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index f6108d61..002e9d9 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -13,8 +13,8 @@
             "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/linux_arm/49b4b5dcbc312d8d2c3751cf29238b8efeb4e494/trace_processor_shell"
         },
         "mac": {
-            "hash": "9eae8ea16e907b5521f3cfbed28b2faca8d1d39d",
-            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/cea074c65731ceb4cbb1985388634c16b4c74479/trace_processor_shell"
+            "hash": "eddbde66f639857ce165158791dcda39985da64d",
+            "full_remote_path": "chromium-telemetry/perfetto_binaries/trace_processor_shell/mac/7bcfdf24e8e973d85a646811ddd6751e8dc8f543/trace_processor_shell"
         },
         "mac_arm64": {
             "hash": "e1ad4861384b06d911a65f035317914b8cc975c6",
diff --git a/tools/typescript/tests/project5/bar_test.ts b/tools/typescript/tests/project5/bar_test.ts
new file mode 100644
index 0000000..4ddb8f9
--- /dev/null
+++ b/tools/typescript/tests/project5/bar_test.ts
@@ -0,0 +1,9 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {foo} from './bar.js';
+
+export function testFoo(): boolean {
+  return foo() == 'foo';
+}
diff --git a/tools/typescript/ts_library.gni b/tools/typescript/ts_library.gni
index f30fc51b..47858eda 100644
--- a/tools/typescript/ts_library.gni
+++ b/tools/typescript/ts_library.gni
@@ -15,10 +15,11 @@
                              "in_files",
                              "tsconfig_base",
                              "manifest_excludes",
+                             "testonly",
                            ])
 
     inputs = [ "//tools/typescript/tsconfig_base.json" ]
-    outputs = [ "$target_gen_dir/tsconfig.json" ]
+    outputs = [ "$target_gen_dir/tsconfig_$target_name.json" ]
 
     assert(defined(in_files) || defined(invoker.definitions))
 
@@ -38,7 +39,7 @@
     }
 
     if (defined(in_files)) {
-      outputs += [ "$target_gen_dir/tsconfig.manifest" ]
+      outputs += [ "$target_gen_dir/$target_name.manifest" ]
       foreach(_source, in_files) {
         inputs += [ "$root_dir/$_source" ]
         _dirname =
@@ -59,6 +60,8 @@
       rebase_path(target_gen_dir, root_build_dir),
       "--out_dir",
       rebase_path(out_dir, root_build_dir),
+      "--output_suffix",
+      target_name,
     ]
 
     if (defined(in_files)) {
@@ -81,9 +84,11 @@
 
     if (defined(deps)) {
       args += [ "--deps" ]
+
       foreach(dep, deps) {
-        args +=
-            [ rebase_path(get_label_info(dep, "dir"), ".") + "/tsconfig.json" ]
+        name = get_label_info(dep, "name")
+        args += [ rebase_path(get_label_info(dep, "dir"), ".") +
+                  "/tsconfig_$name.json" ]
       }
     }
 
diff --git a/tools/typescript/ts_library.py b/tools/typescript/ts_library.py
index 3708925..491b8b9f 100644
--- a/tools/typescript/ts_library.py
+++ b/tools/typescript/ts_library.py
@@ -19,11 +19,11 @@
 import node_modules
 
 
-def _write_tsconfig_json(gen_dir, tsconfig):
+def _write_tsconfig_json(gen_dir, tsconfig, tsconfig_file):
   if not os.path.exists(gen_dir):
     os.makedirs(gen_dir)
 
-  with open(os.path.join(gen_dir, 'tsconfig.json'), 'w') as generated_tsconfig:
+  with open(os.path.join(gen_dir, tsconfig_file), 'w') as generated_tsconfig:
     json.dump(tsconfig, generated_tsconfig, indent=2)
   return
 
@@ -52,6 +52,7 @@
   parser.add_argument('--manifest_excludes', nargs='*')
   parser.add_argument('--definitions', nargs='*')
   parser.add_argument('--composite', action='store_true')
+  parser.add_argument('--output_suffix', required=True)
   args = parser.parse_args(argv)
 
   root_dir = os.path.relpath(args.root_dir, args.gen_dir)
@@ -76,7 +77,7 @@
   tsconfig['compilerOptions']['outDir'] = out_dir
 
   if args.composite:
-    tsbuildinfo_name = 'tsconfig.tsbuildinfo'
+    tsbuildinfo_name = f'tsconfig_{args.output_suffix}.tsbuildinfo'
     tsconfig['compilerOptions']['composite'] = True
     tsconfig['compilerOptions']['declaration'] = True
     tsconfig['compilerOptions']['tsBuildInfoFile'] = tsbuildinfo_name
@@ -100,7 +101,8 @@
   if args.deps is not None:
     tsconfig['references'] = [{'path': dep} for dep in args.deps]
 
-  _write_tsconfig_json(args.gen_dir, tsconfig)
+  tsconfig_file = f'tsconfig_{args.output_suffix}.json'
+  _write_tsconfig_json(args.gen_dir, tsconfig, tsconfig_file)
 
   # Detect and delete obsolete files that can cause build problems.
   if args.in_files is not None:
@@ -136,7 +138,7 @@
   try:
     node.RunNode([
         node_modules.PathToTypescript(), '--project',
-        os.path.join(args.gen_dir, 'tsconfig.json')
+        os.path.join(args.gen_dir, tsconfig_file)
     ])
   finally:
     if args.composite:
@@ -156,8 +158,9 @@
         os.remove(tsbuildinfo_path)
 
   if args.in_files is not None:
-    with open(os.path.join(args.gen_dir, 'tsconfig.manifest'), 'w') \
-        as manifest_file:
+
+    manifest_path = os.path.join(args.gen_dir, f'{args.output_suffix}.manifest')
+    with open(manifest_path, 'w') as manifest_file:
       manifest_data = {}
       manifest_data['base_dir'] = args.out_dir
       manifest_files = args.in_files
diff --git a/tools/typescript/ts_library_test.py b/tools/typescript/ts_library_test.py
index d9fac64..bf72f66 100755
--- a/tools/typescript/ts_library_test.py
+++ b/tools/typescript/ts_library_test.py
@@ -40,6 +40,8 @@
 
     # Build project1, which includes a mix of TS and definition files.
     ts_library.main([
+        '--output_suffix',
+        'build_ts',
         '--root_dir',
         os.path.join(_HERE_DIR, 'tests', 'project1'),
         '--gen_dir',
@@ -60,14 +62,14 @@
         'foo.js',
         'legacy_file.d.ts',
         'tsconfig_definitions.json',
-        'tsconfig.json',
-        'tsconfig.manifest',
+        'tsconfig_build_ts.json',
+        'build_ts.manifest',
     ]
     for f in files:
       self.assertTrue(os.path.exists(os.path.join(gen_dir, f)), f)
 
     # Check that the generated .tsbuildinfo file is deleted.
-    tsbuildinfo = 'tsconfig.tsbuildinfo'
+    tsbuildinfo = 'tsconfig_build_ts.tsbuildinfo'
     self.assertFalse(os.path.exists(os.path.join(gen_dir, tsbuildinfo)),
                      tsbuildinfo)
 
@@ -80,6 +82,8 @@
     project3_gen_dir = os.path.relpath(project3_gen_dir, gen_dir)
 
     ts_library.main([
+        '--output_suffix',
+        'build_ts',
         '--root_dir',
         root_dir,
         '--gen_dir',
@@ -89,8 +93,8 @@
         '--in_files',
         'bar.ts',
         '--deps',
-        os.path.join(project1_gen_dir, 'tsconfig.json'),
-        os.path.join(project3_gen_dir, 'tsconfig.json'),
+        os.path.join(project1_gen_dir, 'tsconfig_build_ts.json'),
+        os.path.join(project3_gen_dir, 'tsconfig_build_ts.json'),
         '--path_mappings',
         'chrome://some-other-source/*|' + os.path.join(project1_gen_dir, '*'),
         '--tsconfig_base',
@@ -101,15 +105,15 @@
   def _assert_project2_output(self, gen_dir):
     files = [
         'bar.js',
-        'tsconfig.json',
-        'tsconfig.manifest',
+        'tsconfig_build_ts.json',
+        'build_ts.manifest',
     ]
     for f in files:
       self.assertTrue(os.path.exists(os.path.join(gen_dir, f)), f)
 
     non_existing_files = [
         'bar.d.ts',
-        'tsconfig.tsbuildinfo',
+        'tsconfig_build_ts.tsbuildinfo',
     ]
     for f in non_existing_files:
       self.assertFalse(os.path.exists(os.path.join(gen_dir, f)), f)
@@ -119,6 +123,8 @@
     gen_dir = os.path.join(self._out_folder, 'project3')
 
     ts_library.main([
+        '--output_suffix',
+        'build_ts',
         '--root_dir',
         os.path.join(_HERE_DIR, 'tests', 'project3'),
         '--gen_dir',
@@ -132,10 +138,11 @@
     return gen_dir
 
   def _assert_project3_output(self, gen_dir):
-    self.assertTrue(os.path.exists(os.path.join(gen_dir, 'tsconfig.json')))
+    self.assertTrue(
+        os.path.exists(os.path.join(gen_dir, 'tsconfig_build_ts.json')))
     self.assertFalse(
-        os.path.exists(os.path.join(gen_dir, 'tsconfig.tsbuildinfo')))
-    self.assertFalse(os.path.exists(os.path.join(gen_dir, 'tsconfig.manifest')))
+        os.path.exists(os.path.join(gen_dir, 'tsconfig_build_ts.tsbuildinfo')))
+    self.assertFalse(os.path.exists(os.path.join(gen_dir, 'build_ts.manifest')))
 
   def _build_project4(self):
     gen_dir = os.path.join(self._out_folder, 'project4')
@@ -143,6 +150,8 @@
     # Build project4, which includes multiple TS files, only one of which should
     # be included in the manifest.
     ts_library.main([
+        '--output_suffix',
+        'build_ts',
         '--root_dir',
         os.path.join(_HERE_DIR, 'tests', 'project4'),
         '--gen_dir',
@@ -161,19 +170,74 @@
     files = [
         'include.js',
         'exclude.js',
-        'tsconfig.json',
-        'tsconfig.manifest',
+        'tsconfig_build_ts.json',
+        'build_ts.manifest',
     ]
     for f in files:
       self.assertTrue(os.path.exists(os.path.join(gen_dir, f)), f)
 
     # Check that the generated manifest file doesn't include exclude.js.
-    manifest = 'tsconfig.manifest'
-    with open(os.path.join(gen_dir, manifest), 'r') as f:
-      data = json.load(f)
-      self.assertEqual(len(data['files']), 1)
-      self.assertEqual(data['files'][0], 'include.js')
+    manifest = os.path.join(gen_dir, 'build_ts.manifest')
+    self._assert_manifest_files(manifest, ['include.js'])
 
+  def _assert_manifest_files(self, manifest_path, expected_files):
+    with open(manifest_path, 'r') as f:
+      data = json.load(f)
+      self.assertEqual(data['files'], expected_files)
+
+  def _build_project5(self):
+    gen_dir = os.path.join(self._out_folder, 'project5')
+    out_dir_test = os.path.join(self._out_folder, 'project5_test')
+
+    # Build project5, which includes 2 TS projects one for prod and one for
+    # test, it should generate different manifest, tsconfig and tsbuildinfo.
+    # prod:
+    ts_library.main([
+        '--output_suffix',
+        'build_ts',
+        '--composite',
+        '--root_dir',
+        os.path.join(_HERE_DIR, 'tests', 'project5'),
+        '--gen_dir',
+        gen_dir,
+        '--out_dir',
+        gen_dir,
+        '--in_files',
+        'bar.ts',
+    ])
+
+    # test:
+    ts_library.main([
+        '--output_suffix',
+        'test_build_ts',
+        '--deps',
+        os.path.join(gen_dir, 'tsconfig_build_ts.json'),
+        '--root_dir',
+        os.path.join(_HERE_DIR, 'tests', 'project5'),
+        '--gen_dir',
+        gen_dir,
+        '--out_dir',
+        gen_dir,
+        '--in_files',
+        'bar_test.ts',
+    ])
+
+    return gen_dir
+
+  def _assert_project5_output(self, gen_dir):
+    # prod:
+    self.assertTrue(
+        os.path.exists(os.path.join(gen_dir, 'tsconfig_build_ts.json')))
+    manifest = os.path.join(gen_dir, 'build_ts.manifest')
+    self.assertTrue(os.path.exists(manifest))
+    self._assert_manifest_files(manifest, ['bar.js'])
+
+    # test:
+    self.assertTrue(
+        os.path.exists(os.path.join(gen_dir, 'tsconfig_test_build_ts.json')))
+    manifest_test = os.path.join(gen_dir, 'test_build_ts.manifest')
+    self.assertTrue(os.path.exists(manifest_test))
+    self._assert_manifest_files(manifest_test, ['bar_test.js'])
 
   # Test success case where both project1 and project2 are compiled successfully
   # and no errors are thrown.
@@ -191,6 +255,9 @@
     project4_gen_dir = self._build_project4()
     self._assert_project4_output(project4_gen_dir)
 
+    project5_gen_dir = self._build_project5()
+    self._assert_project5_output(project5_gen_dir)
+
   # Test error case where a type violation exists, ensure that an error is
   # thrown.
   def testError(self):
@@ -198,6 +265,8 @@
     gen_dir = os.path.join(self._out_folder, 'project1')
     try:
       ts_library.main([
+          '--output_suffix',
+          'build_ts',
           '--root_dir',
           os.path.join(_HERE_DIR, 'tests', 'project1'),
           '--gen_dir',
@@ -212,7 +281,8 @@
       self.assertTrue('Type \'number\' is not assignable to type \'string\'' \
                       in str(err))
       self.assertFalse(
-          os.path.exists(os.path.join(gen_dir, 'tsconfig.tsbuildinfo')))
+          os.path.exists(os.path.join(gen_dir,
+                                      'tsconfig_build_ts.tsbuildinfo')))
     else:
       self.fail('Failed to detect type error')
 
@@ -223,6 +293,8 @@
     gen_dir = os.path.join(self._out_folder, 'project5')
     try:
       ts_library.main([
+          '--output_suffix',
+          'build_ts',
           '--root_dir',
           root_dir,
           '--gen_dir',
diff --git a/ui/chromeos/file_manager_strings.grdp b/ui/chromeos/file_manager_strings.grdp
index 91e1980..e8f91272 100644
--- a/ui/chromeos/file_manager_strings.grdp
+++ b/ui/chromeos/file_manager_strings.grdp
@@ -512,6 +512,9 @@
   <message name="IDS_FILE_BROWSER_MANAGE_IN_DRIVE_BUTTON_LABEL" desc="Menu item's label, showing dialog to open the selected Google Drive files in the Drive webpage for managing sharing permissions, etc.">
     Manage in Drive
   </message>
+  <message name="IDS_FILE_BROWSER_DRIVE_MANAGE_MIRRORSYNC_LABEL" desc="Menu item's label, shows dialog to manage MirrorSync settings and currently syncing folders.">
+    Manage synced folders
+  </message>
   <message name="IDS_FILE_BROWSER_SHARE_WITH_LINUX_BUTTON_LABEL" desc="Label for menu that will share a folder with the crostini Linux container.">
     Share with Linux
   </message>
diff --git a/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DRIVE_MANAGE_MIRRORSYNC_LABEL.png.sha1 b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DRIVE_MANAGE_MIRRORSYNC_LABEL.png.sha1
new file mode 100644
index 0000000..307cbdb
--- /dev/null
+++ b/ui/chromeos/file_manager_strings_grdp/IDS_FILE_BROWSER_DRIVE_MANAGE_MIRRORSYNC_LABEL.png.sha1
@@ -0,0 +1 @@
+f100ec4a3d5cd3c845ca4135499519c426ad51b2
\ No newline at end of file
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 2f7f49f7..b236dc8e 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -137,6 +137,39 @@
   ]
 }
 
+ts_library("build_ts") {
+  root_dir = preprocess_folder
+  out_dir = "$target_gen_dir/tsc"
+  tsconfig_base = "tsconfig_base.json"
+
+  extra_deps = [
+    ":copy_ts",
+    ":preprocess_generated",
+    ":preprocess_generated_image_loader",
+    ":preprocess_static",
+    ":preprocess_static_image_loader",
+  ]
+
+  deps = [ "//ui/webui/resources:library" ]
+
+  in_files =
+      static_js_files + generated_js_files + ts_files + ts_generated_templates +
+      image_loader_static_js_files + image_loader_generated_js_files
+
+  definitions = [
+    "//ui/file_manager/file_manager/definitions/file_manager.d.ts",
+    "//ui/file_manager/file_manager/definitions/volume_manager.d.ts",
+  ]
+}
+
+js_library("js_from_ts") {
+  sources = []
+  foreach(_t, ts_files) {
+    sources += [ "$target_gen_dir/tsc/" + string_replace(_t, ".ts", ".js") ]
+  }
+  extra_deps = [ ":build_ts" ]
+}
+
 grd_prefix = "file_manager_gen"
 generated_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
 
@@ -215,7 +248,8 @@
       "//ui/file_manager/file_manager/foreground/js:build_worker",
     ]
   } else {
-    manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+    manifest_files =
+        filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   }
 }
 
@@ -247,39 +281,6 @@
   in_files = ts_templates
 }
 
-ts_library("build_ts") {
-  root_dir = preprocess_folder
-  out_dir = "$target_gen_dir/tsc"
-  tsconfig_base = "tsconfig_base.json"
-
-  extra_deps = [
-    ":copy_ts",
-    ":preprocess_generated",
-    ":preprocess_generated_image_loader",
-    ":preprocess_static",
-    ":preprocess_static_image_loader",
-  ]
-
-  deps = [ "//ui/webui/resources:library" ]
-
-  in_files =
-      static_js_files + generated_js_files + ts_files + ts_generated_templates +
-      image_loader_static_js_files + image_loader_generated_js_files
-
-  definitions = [
-    "//ui/file_manager/file_manager/definitions/file_manager.d.ts",
-    "//ui/file_manager/file_manager/definitions/volume_manager.d.ts",
-  ]
-}
-
-js_library("js_from_ts") {
-  sources = []
-  foreach(_t, ts_files) {
-    sources += [ "$target_gen_dir/tsc/" + string_replace(_t, ".ts", ".js") ]
-  }
-  extra_deps = [ ":build_ts" ]
-}
-
 # GRD for test files.
 generate_grd("build_tests_grdp") {
   testonly = true
@@ -296,6 +297,8 @@
   grd_prefix = "file_manager_test"
   out_grd = "$target_gen_dir/tests_gen_resources.grdp"
 
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+
   deps = [ ":build_ts" ]
 }
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 58844e16..774b431 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1380,6 +1380,16 @@
 };
 
 /**
+ * Returns true if DriveFsMirroring flag is enabled.
+ * @return {boolean}
+ */
+util.isMirrorSyncEnabled = () => {
+  return loadTimeData.isInitialized() &&
+      loadTimeData.valueExists('DRIVEFS_MIRRORING') &&
+      loadTimeData.getBoolean('DRIVEFS_MIRRORING');
+};
+
+/**
  * Retrieves all entries inside the given |rootEntry|.
  * @param {!DirectoryEntry} rootEntry
  * @param {function(!Array<!Entry>)} entriesCallback Called when some chunk of
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index e1259e6..5d28934 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -2358,6 +2358,30 @@
 })();
 
 /**
+ * Opens the Manage MirrorSync dialog if the flag is enabled.
+ */
+CommandHandler.COMMANDS_['manage-mirrorsync'] =
+    new (class extends FilesCommand {
+      execute(event, fileManager) {
+        // TODO(b/237066325): Wire this up to the `ManageMirrorSyncDialog`.
+      }
+
+      /**
+       * @override
+       */
+      canExecute(event, fileManager) {
+        // MirrorSync is only available to sync local directories, only show the
+        // folder when navigated to a local directory.
+        const currentRootType = fileManager.directoryModel.getCurrentRootType();
+        event.canExecute =
+            (currentRootType === VolumeManagerCommon.RootType.MY_FILES ||
+             currentRootType === VolumeManagerCommon.RootType.DOWNLOADS) &&
+            util.isMirrorSyncEnabled();
+        event.command.setHidden(!event.canExecute);
+      }
+    })();
+
+/**
  * Shares the selected (single only) directory with the default crostini VM.
  */
 CommandHandler.COMMANDS_['share-with-linux'] = new (class extends FilesCommand {
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 1cf11f4..ea52e96 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -137,6 +137,8 @@
                shortcut="." hide-shortcut-text>
       <command id="manage-in-drive"
                label="$i18n{MANAGE_IN_DRIVE_BUTTON_LABEL}" disabled hidden>
+      <command id="manage-mirrorsync"
+               label="$i18n{DRIVE_MANAGE_MIRRORSYNC}" disabled hidden>
       <command id="share-with-linux" label="$i18n{SHARE_WITH_LINUX_BUTTON_LABEL}" disabled hidden>
       <command id="manage-linux-sharing" label="$i18n{MANAGE_LINUX_SHARING_BUTTON_LABEL}" disabled hidden>
       <command id="manage-linux-sharing-gear" label="$i18n{MANAGE_LINUX_SHARING_BUTTON_LABEL}" disabled hidden>
@@ -276,6 +278,8 @@
                       command="#manage-plugin-vm-sharing-gear"></cr-menu-item>
         <cr-menu-item id="gear-menu-drive-sync-settings"
                       command="#drive-sync-settings"></cr-menu-item>
+        <cr-menu-item id="gear-menu-manage-mirrorsync"
+                      command="#manage-mirrorsync"></cr-menu-item>
         <hr id="help-separator">
         <cr-menu-item id="gear-menu-drive-buy-more-space"
                       command="#drive-buy-more-space"></cr-menu-item>
diff --git a/ui/file_manager/integration_tests/file_manager/gear_menu.js b/ui/file_manager/integration_tests/file_manager/gear_menu.js
index 3a24300..0dc1b67 100644
--- a/ui/file_manager/integration_tests/file_manager/gear_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/gear_menu.js
@@ -677,3 +677,51 @@
           '[command=\'#volume-storage\']' +
           ':not([hidden])');
 };
+
+/**
+ * Test that the "Mange synced folders" gear menu item is hidden and is also
+ * disabled when the DriveFsMirroring flag is disabled.
+ */
+testcase.showManageMirrorSyncShowsOnlyInLocalRoot = async () => {
+  // Open Files app on Downloads containing ENTRIES.photos.
+  const appId =
+      await setupAndWaitUntilReady(RootPath.DOWNLOADS, [ENTRIES.photos], []);
+
+  // Wait for the gear menu button to appear and click it.
+  await remoteCall.waitAndClickElement(appId, '#gear-button');
+
+  // Wait for the gear menu to appear.
+  await remoteCall.waitForElement(appId, '#gear-menu:not([hidden])');
+
+  // If the flag is disabled, the "Manage synced folders" menu item should be
+  // hidden and disabled.
+  if ((await sendTestMessage({name: 'isMirrorSyncEnabled'})) === 'false') {
+    await remoteCall.waitForElement(
+        appId,
+        '#gear-menu:not([hidden]) cr-menu-item' +
+            '[command=\'#manage-mirrorsync\'][disabled][hidden]');
+    return;
+  }
+
+  // The "Manage synced folders" item should be visible and enabled.
+  await remoteCall.waitForElement(
+      appId,
+      '#gear-menu:not([hidden]) cr-menu-item' +
+          '[command=\'#manage-mirrorsync\']:not([disabled][hidden])');
+
+  // Navigate to the Google Drive root.
+  await navigateWithDirectoryTree(appId, '/My Drive');
+
+  // Wait for the gear menu button to appear and click it.
+  await remoteCall.waitAndClickElement(appId, '#gear-button');
+
+  // Wait for the gear menu to appear.
+  await remoteCall.waitForElement(appId, '#gear-menu:not([hidden])');
+
+  // The "Manage synced folders" item should not be visible and should be
+  // disabled.
+  await remoteCall.waitForElement(
+      appId,
+      '#gear-menu:not([hidden]) cr-menu-item' +
+          '[command=\'#manage-mirrorsync\'][disabled][hidden]');
+};
diff --git a/ui/gl/gl_display.h b/ui/gl/gl_display.h
index a55edd5..46030cf 100644
--- a/ui/gl/gl_display.h
+++ b/ui/gl/gl_display.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <vector>
 
 #include "ui/gl/gl_export.h"
 
diff --git a/ui/views/debug_utils.cc b/ui/views/debug_utils.cc
index 7e4c8660..293c656 100644
--- a/ui/views/debug_utils.cc
+++ b/ui/views/debug_utils.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "ui/compositor/layer.h"
 #include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
 
 #if !defined(NDEBUG)
 #include "ui/gfx/geometry/angle_conversions.h"
@@ -143,6 +144,41 @@
 
 }  // namespace
 
+void PrintWidgetInformation(const Widget& widget,
+                            bool detailed,
+                            std::ostringstream* out) {
+  *out << " name=" << widget.GetName();
+  *out << " (" << &widget << ")";
+
+  if (widget.parent())
+    *out << " parent=" << widget.parent();
+  else
+    *out << " parent=none";
+
+  const ui::Layer* layer = widget.GetLayer();
+  if (layer)
+    *out << " layer=" << layer;
+  else
+    *out << " layer=none";
+
+  *out << (widget.is_top_level() ? " [top_level]" : " [!top_level]");
+
+  if (detailed) {
+    *out << (widget.IsActive() ? " [active]" : " [!active]");
+    *out << (widget.IsVisible() ? " [visible]" : " [!visible]");
+  }
+
+  *out << (widget.IsClosed() ? " [closed]" : "");
+  *out << (widget.IsMaximized() ? " [maximized]" : "");
+  *out << (widget.IsMinimized() ? " [minimized]" : "");
+  *out << (widget.IsFullscreen() ? " [fullscreen]" : "");
+
+  if (detailed)
+    *out << " " << widget.GetWindowBoundsInScreen().ToString();
+
+  *out << '\n';
+}
+
 void PrintViewHierarchy(const View* view) {
   std::ostringstream out;
   PrintViewHierarchy(view, &out);
diff --git a/ui/views/debug_utils.h b/ui/views/debug_utils.h
index 6d0d9cd0..e86c6c7 100644
--- a/ui/views/debug_utils.h
+++ b/ui/views/debug_utils.h
@@ -5,6 +5,7 @@
 #ifndef UI_VIEWS_DEBUG_UTILS_H_
 #define UI_VIEWS_DEBUG_UTILS_H_
 
+#include <sstream>
 #include <string>
 
 #include "ui/views/views_export.h"
@@ -12,6 +13,7 @@
 namespace views {
 
 class View;
+class Widget;
 
 // Log the view hierarchy.
 VIEWS_EXPORT void PrintViewHierarchy(const View* view);
@@ -22,6 +24,12 @@
 // Log the focus traversal hierarchy.
 VIEWS_EXPORT void PrintFocusHierarchy(const View* view);
 
+// Log the information of the widget to |out|. |detailed| controls the amount of
+// information logged.
+VIEWS_EXPORT void PrintWidgetInformation(const Widget& widget,
+                                         bool detailed,
+                                         std::ostringstream* out);
+
 #if !defined(NDEBUG)
 // Returns string containing a graph of the views hierarchy in graphViz DOT
 // language (http://graphviz.org/). Can be called within debugger and saved
diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn
index c7fd5e37..71a0e9d 100644
--- a/ui/webui/resources/BUILD.gn
+++ b/ui/webui/resources/BUILD.gn
@@ -160,13 +160,6 @@
 
 preprocessed_folder = "$target_gen_dir/preprocessed"
 
-generate_grd("build_ts_grdp") {
-  grd_prefix = "webui"
-  out_grd = "$target_gen_dir/resources_ts.grdp"
-  public_deps = [ ":library" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-}
-
 checked_in_dts_files = [
   "cr_elements/cr_button/cr_button.m.d.ts",
   "cr_elements/cr_checkbox/cr_checkbox.m.d.ts",
@@ -434,6 +427,14 @@
   ]
 }
 
+generate_grd("build_ts_grdp") {
+  grd_prefix = "webui"
+  out_grd = "$target_gen_dir/resources_ts.grdp"
+  public_deps = [ ":library" ]
+  manifest_files =
+      filter_include(get_target_outputs(":library"), [ "*.manifest" ])
+}
+
 ts_definitions("generate_definitions") {
   root_dir = preprocessed_folder
   out_dir = preprocessed_folder
diff --git a/ui/webui/resources/cr_components/app_management/BUILD.gn b/ui/webui/resources/cr_components/app_management/BUILD.gn
index 4855a2e..2043f861 100644
--- a/ui/webui/resources/cr_components/app_management/BUILD.gn
+++ b/ui/webui/resources/cr_components/app_management/BUILD.gn
@@ -140,7 +140,8 @@
   grd_prefix = "cr_components_app_management"
   out_grd = "$target_gen_dir/resources.grdp"
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "cr_components/app_management"
 }
 
diff --git a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
index 33d7ddec..a3413715 100644
--- a/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
+++ b/ui/webui/resources/cr_components/certificate_manager/BUILD.gn
@@ -64,6 +64,7 @@
   grd_prefix = "cr_components_certificate_manager"
   out_grd = "$target_gen_dir/resources.grdp"
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "cr_components/certificate_manager"
 }
diff --git a/ui/webui/resources/cr_components/color_change_listener/BUILD.gn b/ui/webui/resources/cr_components/color_change_listener/BUILD.gn
index 37a1753e..3fad7e0 100644
--- a/ui/webui/resources/cr_components/color_change_listener/BUILD.gn
+++ b/ui/webui/resources/cr_components/color_change_listener/BUILD.gn
@@ -51,6 +51,7 @@
   grd_prefix = "cr_components_color_change_listener"
   out_grd = "$target_gen_dir/resources.grdp"
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "cr_components/color_change_listener"
 }
diff --git a/ui/webui/resources/cr_components/customize_themes/BUILD.gn b/ui/webui/resources/cr_components/customize_themes/BUILD.gn
index 060c24d..0bf17d9 100644
--- a/ui/webui/resources/cr_components/customize_themes/BUILD.gn
+++ b/ui/webui/resources/cr_components/customize_themes/BUILD.gn
@@ -79,6 +79,7 @@
     "brush.svg",
   ]
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "cr_components/customize_themes"
 }
diff --git a/ui/webui/resources/cr_components/help_bubble/BUILD.gn b/ui/webui/resources/cr_components/help_bubble/BUILD.gn
index 9791052..cbe4967 100644
--- a/ui/webui/resources/cr_components/help_bubble/BUILD.gn
+++ b/ui/webui/resources/cr_components/help_bubble/BUILD.gn
@@ -72,6 +72,7 @@
   grd_prefix = "cr_components_help_bubble"
   out_grd = "$target_gen_dir/resources.grdp"
   deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "cr_components/help_bubble"
 }
diff --git a/ui/webui/resources/cr_components/history_clusters/BUILD.gn b/ui/webui/resources/cr_components/history_clusters/BUILD.gn
index 1528e25..f5739f71 100644
--- a/ui/webui/resources/cr_components/history_clusters/BUILD.gn
+++ b/ui/webui/resources/cr_components/history_clusters/BUILD.gn
@@ -42,14 +42,6 @@
   deps = [ ":mojo_bindings_webui_js" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "cr_components_history_clusters"
-  out_grd = "$target_gen_dir/resources.grdp"
-  public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "cr_components/history_clusters"
-}
-
 preprocess_if_expr("preprocess") {
   in_folder = "."
   out_folder = preprocess_folder_tmp
@@ -85,3 +77,12 @@
     ":preprocess_generated",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "cr_components_history_clusters"
+  out_grd = "$target_gen_dir/resources.grdp"
+  public_deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "cr_components/history_clusters"
+}
diff --git a/ui/webui/resources/cr_components/most_visited/BUILD.gn b/ui/webui/resources/cr_components/most_visited/BUILD.gn
index f2568f6..cf37adc 100644
--- a/ui/webui/resources/cr_components/most_visited/BUILD.gn
+++ b/ui/webui/resources/cr_components/most_visited/BUILD.gn
@@ -38,15 +38,6 @@
   outputs = [ "$target_gen_dir/{{source_file_part}}" ]
 }
 
-generate_grd("build_grdp") {
-  grd_prefix = "cr_components_most_visited"
-  out_grd = "$target_gen_dir/resources.grdp"
-
-  public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
-  resource_path_prefix = "cr_components/most_visited"
-}
-
 ts_library("build_ts") {
   root_dir = target_gen_dir
   out_dir = preprocess_folder
@@ -64,3 +55,13 @@
     ":html_wrapper_files",
   ]
 }
+
+generate_grd("build_grdp") {
+  grd_prefix = "cr_components_most_visited"
+  out_grd = "$target_gen_dir/resources.grdp"
+
+  public_deps = [ ":build_ts" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
+  resource_path_prefix = "cr_components/most_visited"
+}
diff --git a/ui/webui/resources/js/BUILD.gn b/ui/webui/resources/js/BUILD.gn
index 9a5568f..a61f00a 100644
--- a/ui/webui/resources/js/BUILD.gn
+++ b/ui/webui/resources/js/BUILD.gn
@@ -24,7 +24,7 @@
     "$target_gen_dir/$preprocess_src_manifest",
   ]
   if (include_polymer) {
-    manifest_files += [ "$target_gen_dir/browser_command/tsconfig.manifest" ]
+    manifest_files += [ "$target_gen_dir/browser_command/build_ts.manifest" ]
   }
   resource_path_prefix = "js"
 }
diff --git a/ui/webui/resources/js/browser_command/BUILD.gn b/ui/webui/resources/js/browser_command/BUILD.gn
index a8210ca..1c81fde 100644
--- a/ui/webui/resources/js/browser_command/BUILD.gn
+++ b/ui/webui/resources/js/browser_command/BUILD.gn
@@ -52,6 +52,7 @@
   grd_prefix = "webui_js_browser_command"
   out_grd = "$target_gen_dir/resources.grdp"
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "js/browser_command"
 }
diff --git a/ui/webui/resources/js/metrics_reporter/BUILD.gn b/ui/webui/resources/js/metrics_reporter/BUILD.gn
index 497ec96..0a08ae9 100644
--- a/ui/webui/resources/js/metrics_reporter/BUILD.gn
+++ b/ui/webui/resources/js/metrics_reporter/BUILD.gn
@@ -48,6 +48,7 @@
   grd_prefix = "webui_js_metrics_reporter"
   out_grd = "$target_gen_dir/resources.grdp"
   public_deps = [ ":build_ts" ]
-  manifest_files = [ "$target_gen_dir/tsconfig.manifest" ]
+  manifest_files =
+      filter_include(get_target_outputs(":build_ts"), [ "*.manifest" ])
   resource_path_prefix = "js/metrics_reporter"
 }