diff --git a/DEPS b/DEPS
index 0f4c6079..32a1420 100644
--- a/DEPS
+++ b/DEPS
@@ -175,7 +175,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:e81c0c9c528d0a416922e4ccd958d0de59a64816',
+  'luci_go': 'git_revision:ea8dc31395c76b2990112b29b02386628d795d2d',
 
   # This can be overridden, e.g. with custom_vars, to build clang from HEAD
   # instead of downloading the prebuilt pinned revision.
@@ -204,11 +204,11 @@
   # 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': 'dc20847579665223826ff5f2d344a0b566e3b4b5',
+  'skia_revision': '1c22e62b710fcf5e81817e487cb63c5b5fc548a2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'fc442e89638f38a476e53abca22aafde28c55aa5',
+  'v8_revision': '4f0f4e2a3c5ad9dc7312774da5197e0179c30863',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -216,7 +216,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3eace05cb270ea7f44ec1ce9dd002ebb8d4a587f',
+  'angle_revision': 'f6eccc203e0f45736103eee629961b865d132d5a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -224,7 +224,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'd3632c0bb902fbb4d9777e70d92d9355f5133bcb',
+  'pdfium_revision': '34cbd9296c60d1c583035e02efe4dd8fc8ebe2c8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -275,7 +275,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': '629e117d9b566e0f1eebde8053cdc94614fd5176',
+  'catapult_revision': 'c730daef7584945290b923a0b72c4ddccf66301b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # 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 nearby
   # and whatever else without interference from each other.
-  'nearby_revision': '8fafd3ef09818e1983945aa8be9663713c79c142',
+  'nearby_revision': 'a7b99e7509c3734b94a151739bc4035de6497a37',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -536,7 +536,7 @@
     Var('chromium_git') + '/external/github.com/toji/webvr.info.git' + '@' + 'c58ae99b9ff9e2aa4c524633519570bf33536248',
 
   'src/ios/third_party/earl_grey2/src': {
-      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '4c95b76bd9abe50620462a34f7a97e6b6812939a',
+      'url': Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '060c4a2c933ded64a5d31bb67e486ffe8e07a204',
       'condition': 'checkout_ios',
   },
 
@@ -696,7 +696,7 @@
     'packages': [
       {
           'package': 'chromium/third_party/androidx',
-          'version': 'xIdmDAvhfStt7ky1enCv_j6NNXqdhajuI8563NJ3QekC',
+          'version': '65fRug8cVwh3hU__E3A3qq1_ITouFc9LU--TbqTw714C',
       },
     ],
     'condition': 'checkout_android',
@@ -858,7 +858,7 @@
   },
 
   'src/third_party/breakpad/breakpad':
-    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'd6a6f52606529111b9f0ade9a0e0d9040fa97c1f',
+    Var('chromium_git') + '/breakpad/breakpad.git' + '@' + 'dff7d5afd51d7e831c44faf30f45f2d2ca02575b',
 
   'src/third_party/byte_buddy': {
       'packages': [
@@ -1537,7 +1537,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '66460536ee975a3e98931b7b40a661a63fd9cd57',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '417361423e789b798185d324241f4ac9bfd09066',
+    Var('webrtc_git') + '/src.git' + '@' + '92a768ad66f54ca57002f6f2e87c7a732e3fec39',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1575,7 +1575,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': '3T-SUsozYAVsudk5nd48kjHvfpos6egORLB8s7ElE8oC',
+          'version': 'NQmBkXHpEXJthTy0c6iuXDk1UgYDyQ7Fm649E7P38bAC',
         },
       ],
       'dep_type': 'cipd',
@@ -1609,7 +1609,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9e64d40cc7c8207b7de94268052944ffb6422ab4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1cd00576f761655a08e4c2efc62db2a76cc9b0fc',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index dd146763..349335c0 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -990,7 +990,7 @@
   def testExpectedPaths(self):
     filesToTest = [
       "chrome/browser/accessibility/foo.py",
-      "chrome/browser/chromeos/arc/accessibility/foo.cc",
+      "chrome/browser/ash/arc/accessibility/foo.cc",
       "chrome/browser/ui/views/accessibility/foo.h",
       "chrome/browser/extensions/api/automation/foo.h",
       "chrome/browser/extensions/api/automation_internal/foo.cc",
diff --git a/WATCHLISTS b/WATCHLISTS
index 26f9125..8bd3541 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -140,7 +140,7 @@
       'filepath': 'arc/',
     },
     'arc_auth': {
-      'filepath': 'chrome/browser/chromeos/arc/arc_auth'
+      'filepath': 'chrome/browser/ash/arc/auth'
     },
     'arc_ime': {
       'filepath': 'chrome/browser/chromeos/arc/input_method_manager/'\
diff --git a/android_webview/common/aw_paths.cc b/android_webview/common/aw_paths.cc
index 1655c35..ed1c0b1 100644
--- a/android_webview/common/aw_paths.cc
+++ b/android_webview/common/aw_paths.cc
@@ -26,6 +26,12 @@
       cur = cur.Append(FILE_PATH_LITERAL("components"))
                 .Append(FILE_PATH_LITERAL("cus"));
       break;
+    case DIR_COMPONENTS_TEMP:
+      if (!base::android::GetCacheDirectory(&cur))
+        return false;
+      cur = cur.Append(FILE_PATH_LITERAL("components"))
+                .Append(FILE_PATH_LITERAL("cus"));
+      break;
     case DIR_SAFE_BROWSING:
       if (!base::android::GetCacheDirectory(&cur))
         return false;
diff --git a/android_webview/common/aw_paths.h b/android_webview/common/aw_paths.h
index e11cb4f..ef0ac5a 100644
--- a/android_webview/common/aw_paths.h
+++ b/android_webview/common/aw_paths.h
@@ -18,6 +18,9 @@
   DIR_COMPONENTS_ROOT,  // Directory where components installed via component
                         // updater.
 
+  DIR_COMPONENTS_TEMP,  // Directory where temporary copies of components are
+                        // made.
+
   DIR_SAFE_BROWSING,  // Directory where safe browsing related cookies are
                       // stored.
 
diff --git a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.cc b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.cc
index 3cf02149f..3addb14 100644
--- a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.cc
+++ b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.cc
@@ -5,22 +5,62 @@
 #include "android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h"
 
 #include <stdint.h>
+
 #include <memory>
 #include <string>
 #include <vector>
 
+#include "android_webview/common/aw_paths.h"
 #include "android_webview/nonembedded/component_updater/aw_component_update_service.h"
+#include "base/android/path_utils.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
 #include "base/notreached.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "components/update_client/update_client_errors.h"
 #include "components/update_client/utils.h"
 
 namespace android_webview {
 
+namespace {
+
+uint32_t GetHighestSequenceNumber(const base::FilePath& base_file_path) {
+  uint32_t highest_sequence_number = 0;
+  base::FileEnumerator file_enumerator(base_file_path, /* recursive= */ false,
+                                       base::FileEnumerator::DIRECTORIES);
+  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+       path = file_enumerator.Next()) {
+    uint32_t sequence_number = 0;
+    std::vector<std::string> dir_name_components =
+        base::SplitString(path.BaseName().MaybeAsASCII(), "_",
+                          base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+    if (dir_name_components.size() >= 2 &&
+        base::StringToUint(dir_name_components[0], &sequence_number)) {
+      highest_sequence_number =
+          std::max(sequence_number, highest_sequence_number);
+    } else {
+      LOG(WARNING) << "FilePath.BaseName isn't on the format of "
+                      "<sequence_number>_<version_number>"
+                   << path;
+    }
+  }
+
+  return highest_sequence_number;
+}
+
+std::string GetVersionDirName(const uint32_t sequence_number,
+                              const std::string& version) {
+  return base::NumberToString(sequence_number) + "_" + version;
+}
+
+}  // namespace
+
 AwComponentInstallerPolicyDelegate::AwComponentInstallerPolicyDelegate(
     const std::vector<uint8_t>& hash)
     : component_id_(update_client::GetCrxIdFromPublicKeyHash(hash)) {}
@@ -28,61 +68,90 @@
 AwComponentInstallerPolicyDelegate::~AwComponentInstallerPolicyDelegate() =
     default;
 
-update_client::CrxInstaller::Result
-AwComponentInstallerPolicyDelegate::OnCustomInstall(
-    const base::DictionaryValue& manifest,
-    const base::FilePath& install_dir) {
-  std::string version_ascii;
-  manifest.GetStringASCII("version", &version_ascii);
-  const base::Version version(version_ascii);
-  if (!version.IsValid()) {
-    return update_client::CrxInstaller::Result(
-        update_client::InstallError::INVALID_VERSION);
-  }
-
-  // Scoped temp dir, the directory is created under the app cache dir.
-  base::ScopedTempDir temp_dir;
-  if (!temp_dir.CreateUniqueTempDir()) {
-    return update_client::CrxInstaller::Result(
-        update_client::InstallError::MOVE_FILES_ERROR);
-  }
-
-  const base::FilePath temp_path =
-      temp_dir.GetPath().AppendASCII(version_ascii);
-  // Copying files to a temp path before passing it to the
-  // ComponentProviderService. This way, the ComponentUpdateService can safely
-  // delete those files even if the ComponentProviderService hasn't finished
-  // copying them yet.
-  // TODO(crbug.com/1176335) use file links to avoid copying files.
-  if (!base::CopyDirectory(install_dir, temp_path,
-                           /* recursive= */ true)) {
-    return update_client::CrxInstaller::Result(
-        update_client::InstallError::MOVE_FILES_ERROR);
-  }
-
-  // ComponentProviderService should take ownership of the temp path.
-  if (AwComponentUpdateService::GetInstance()->NotifyNewVersion(
-          component_id_, temp_path, version)) {
-    return update_client::CrxInstaller::Result(
-        update_client::InstallError::NONE);
-  }
-
-  return update_client::CrxInstaller::Result(
-      update_client::InstallError::GENERIC_ERROR);
-}
-
 void AwComponentInstallerPolicyDelegate::OnCustomUninstall() {
   // Uninstallation isn't supported in WebView.
   NOTREACHED();
 }
 
+// Copy the components file from `install_dir` to the serving directory of the
+// java `ComponentsProviderService`. `ComponentsProviderService` serving dir is
+// of the form:
+//
+// <data-dir>/components/cps/<component_id>/<sequence_number>_<version>/...
+//
+// where `sequence_number` is strictly increasing unsigned integer, with the
+// most recent version having the highest `sequence_number`.
+//
+// Say that there are two versions: .../<sequence_number_1>_<version_1>/ and
+// .../<sequence_number_2>_<version_2>/. If `sequence_number_2` >
+// `sequence_number_1`, this doesn't necessarily mean that `version_2` >
+// `version_1`.
+//
+// Since this called whenever a valid version is available on disk even if it's
+// not recently installed. To avoid doing unneccessry file copying, if the
+// highest sequence number maps to the same `version`, this will be a NOOP.
+//
+// The reason we use a separate sequence number is to make
+// `ComponentsProviderService` agnostic to the actual version of the component.
+// `ComponentsProviderService` will choose the component with the highest
+// sequence number regardless of its version. This will help to tolerate
+// downgrading of components versions in the future.
+//
+// Directories format should be kept in sync with `ComponentsProviderService`
+// java class.
 void AwComponentInstallerPolicyDelegate::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
     std::unique_ptr<base::DictionaryValue> manifest) {
-  // This is usually when components files are parsed and loaded into memory.
-  // This has to be a NOOP because this runs in a nonembedded WebView process
-  // outside of a browser context.
+  base::FilePath cps_component_base_path =
+      GetComponentsProviderServiceDirectory();
+
+  uint32_t highest_sequence_number =
+      GetHighestSequenceNumber(cps_component_base_path);
+
+  // Do nothing, if the highest sequence number refers to the same `version`.
+  if (base::PathExists(cps_component_base_path.AppendASCII(
+          GetVersionDirName(highest_sequence_number, version.GetString())))) {
+    return;
+  }
+
+  base::FilePath temp_path_root;
+  DCHECK(base::PathService::Get(DIR_COMPONENTS_TEMP, &temp_path_root));
+
+  base::ScopedTempDir temp_dir;
+  if (!temp_dir.CreateUniqueTempDirUnderPath(temp_path_root)) {
+    LOG(WARNING) << "Error creating temp tile under " << temp_path_root;
+    return;
+  }
+
+  const std::string new_sequence_version_string =
+      GetVersionDirName(highest_sequence_number + 1, version.GetString());
+  const base::FilePath temp_copy_path =
+      temp_dir.GetPath().AppendASCII(new_sequence_version_string);
+  // TODO(crbug.com/1176335) use file links to optimize copies number.
+  if (!base::CopyDirectory(install_dir, temp_copy_path,
+                           /* recursive= */ true)) {
+    LOG(WARNING) << "Error copying from " << install_dir << " to "
+                 << temp_copy_path;
+    return;
+  }
+
+  const base::FilePath dest_path =
+      cps_component_base_path.AppendASCII(new_sequence_version_string);
+  // Always attempt to create the base dir just in case if it doesn't exist.
+  base::CreateDirectory(cps_component_base_path);
+  LOG_IF(WARNING, !base::Move(temp_copy_path, dest_path))
+      << "Error moving from " << temp_copy_path << " to " << dest_path;
+}
+
+base::FilePath
+AwComponentInstallerPolicyDelegate::GetComponentsProviderServiceDirectory() {
+  base::FilePath path;
+  DCHECK(base::android::GetDataDirectory(&path))
+      << "Couldn't get Android data directory";
+  return path.AppendASCII("components")
+      .AppendASCII("cps")
+      .AppendASCII(component_id_);
 }
 
 }  // namespace android_webview
diff --git a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h
index e7400f10..a15bccc4 100644
--- a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h
+++ b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h
@@ -38,15 +38,14 @@
       const AwComponentInstallerPolicyDelegate&) = delete;
 
   // These methods should match the methods in ComponentInstallerPolicy
-  update_client::CrxInstaller::Result OnCustomInstall(
-      const base::DictionaryValue& manifest,
-      const base::FilePath& install_dir);
   void OnCustomUninstall();
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
                       std::unique_ptr<base::DictionaryValue> manifest);
 
  private:
+  base::FilePath GetComponentsProviderServiceDirectory();
+
   const std::string component_id_;
 };
 
diff --git a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate_unittest.cc b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate_unittest.cc
index ae55c74..1dd25f08 100644
--- a/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate_unittest.cc
+++ b/android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate_unittest.cc
@@ -5,19 +5,19 @@
 #include "android_webview/nonembedded/component_updater/aw_component_installer_policy_delegate.h"
 
 #include <stdint.h>
+
 #include <iterator>
 #include <memory>
 #include <utility>
 
-#include "android_webview/nonembedded/component_updater/aw_component_update_service.h"
+#include "android_webview/common/aw_paths.h"
+#include "base/android/path_utils.h"
+#include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/task/thread_pool/thread_pool_instance.h"
+#include "base/test/scoped_path_override.h"
 #include "base/values.h"
 #include "base/version.h"
-#include "components/component_updater/component_installer.h"
-#include "components/update_client/update_client.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace android_webview {
@@ -31,15 +31,15 @@
     0x54, 0xb0, 0xd2, 0xdd, 0xa5, 0x6e, 0x05, 0x6b, 0xe8, 0x73, 0x47,
     0xf6, 0xc4, 0x11, 0x9f, 0xbc, 0xb3, 0x09, 0xb3, 0x5b, 0x40};
 
-constexpr char kTestVersion[] = "123.456.789";
-
-std::unique_ptr<base::DictionaryValue> test_manifest() {
+std::unique_ptr<base::DictionaryValue> test_manifest(
+    const base::Version& version) {
   auto manifest = std::make_unique<base::DictionaryValue>();
-  manifest->SetString("version", kTestVersion);
+  manifest->SetString("version", version.GetString());
   return manifest;
 }
 
 void CreateTestFiles(const base::FilePath& install_dir) {
+  base::CreateDirectory(install_dir);
   ASSERT_TRUE(base::WriteFile(install_dir.AppendASCII("file1.txt"), "1"));
   ASSERT_TRUE(base::WriteFile(install_dir.AppendASCII("file2.txt"), "2"));
   ASSERT_TRUE(base::CreateDirectory(install_dir.AppendASCII("sub_dir")));
@@ -55,84 +55,8 @@
       install_dir.AppendASCII("sub_dir").AppendASCII("file3.txt")));
 }
 
-class MockInstallerPolicy : public component_updater::ComponentInstallerPolicy {
- public:
-  MockInstallerPolicy() {
-    std::vector<uint8_t> hash;
-    GetHash(&hash);
-    delegate_ = std::make_unique<AwComponentInstallerPolicyDelegate>(hash);
-  }
-  ~MockInstallerPolicy() override = default;
-
-  MockInstallerPolicy(const MockInstallerPolicy&) = delete;
-  MockInstallerPolicy& operator=(const MockInstallerPolicy&) = delete;
-
-  update_client::CrxInstaller::Result OnCustomInstall(
-      const base::DictionaryValue& manifest,
-      const base::FilePath& install_dir) override {
-    return delegate_->OnCustomInstall(manifest, install_dir);
-  }
-
-  void ComponentReady(
-      const base::Version& version,
-      const base::FilePath& install_dir,
-      std::unique_ptr<base::DictionaryValue> manifest) override {
-    delegate_->ComponentReady(version, install_dir, std::move(manifest));
-  }
-
-  void OnCustomUninstall() override { delegate_->OnCustomUninstall(); }
-
-  MOCK_CONST_METHOD2(VerifyInstallation,
-                     bool(const base::DictionaryValue& manifest,
-                          const base::FilePath& dir));
-  MOCK_CONST_METHOD0(SupportsGroupPolicyEnabledComponentUpdates, bool());
-  MOCK_CONST_METHOD0(RequiresNetworkEncryption, bool());
-  MOCK_CONST_METHOD0(GetRelativeInstallDir, base::FilePath());
-  MOCK_CONST_METHOD0(GetName, std::string());
-  MOCK_CONST_METHOD0(GetInstallerAttributes,
-                     update_client::InstallerAttributes());
-
-  void GetHash(std::vector<uint8_t>* hash) const override {
-    hash->assign(std::begin(kSha256Hash), std::end(kSha256Hash));
-  }
-
- private:
-  std::unique_ptr<AwComponentInstallerPolicyDelegate> delegate_;
-};
-
 }  // namespace
 
-class MockAwComponentUpdateService : public AwComponentUpdateService {
- public:
-  explicit MockAwComponentUpdateService(bool notify_result)
-      : notify_result_(notify_result) {}
-  ~MockAwComponentUpdateService() override = default;
-
-  bool NotifyNewVersion(const std::string& component_id,
-                        const base::FilePath& install_dir,
-                        const base::Version& version) override {
-    component_id_ = component_id;
-    install_dir_ = install_dir;
-    version_ = version;
-
-    // Check that all files are copied to the new install_dir.
-    AssertTestFiles(install_dir_);
-
-    return notify_result_;
-  }
-
-  std::string GetComponentId() const { return component_id_; }
-  base::FilePath GetNewInstallDir() const { return install_dir_; }
-  base::Version GetVersion() const { return version_; }
-
- private:
-  const bool notify_result_;
-
-  std::string component_id_;
-  base::FilePath install_dir_;
-  base::Version version_;
-};
-
 class AwComponentInstallerPolicyDelegateTest : public testing::Test {
  public:
   AwComponentInstallerPolicyDelegateTest() = default;
@@ -143,15 +67,26 @@
   AwComponentInstallerPolicyDelegateTest& operator=(
       const AwComponentInstallerPolicyDelegateTest&) = delete;
 
-  static void SetUpTestSuite() {
-    base::ThreadPoolInstance::CreateAndStartWithDefaultParams(
-        "ComponentInstallerPolicyDelegateTest");
-  }
-
   // Override from testing::Test
   void SetUp() override {
-    mock_policy_ = std::make_unique<MockInstallerPolicy>();
+    scoped_path_override_ =
+        std::make_unique<base::ScopedPathOverride>(DIR_COMPONENTS_TEMP);
+
+    ASSERT_TRUE(base::android::GetDataDirectory(&cps_component_path_));
+    cps_component_path_ = cps_component_path_.AppendASCII("components")
+                              .AppendASCII("cps")
+                              .AppendASCII(kComponentId);
+
     ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+    CreateTestFiles(GetTestInstallPath());
+
+    std::vector<uint8_t> hash;
+    hash.assign(std::begin(kSha256Hash), std::end(kSha256Hash));
+    delegate_ = std::make_unique<AwComponentInstallerPolicyDelegate>(hash);
+  }
+
+  void TearDown() override {
+    ASSERT_TRUE(base::DeletePathRecursively(cps_component_path_));
   }
 
   base::FilePath GetTestInstallPath() const {
@@ -159,43 +94,65 @@
   }
 
  protected:
-  std::unique_ptr<MockInstallerPolicy> mock_policy_;
+  base::FilePath cps_component_path_;
+  std::unique_ptr<AwComponentInstallerPolicyDelegate> delegate_;
 
  private:
   base::ScopedTempDir scoped_temp_dir_;
+  std::unique_ptr<base::ScopedPathOverride> scoped_path_override_;
 };
 
-TEST_F(AwComponentInstallerPolicyDelegateTest,
-       TestSuccessfullNotifyNewVersion) {
-  MockAwComponentUpdateService mock_service(/* notify_result= */ true);
-  SetAwComponentUpdateServiceForTesting(&mock_service);
-  CreateTestFiles(GetTestInstallPath());
+TEST_F(AwComponentInstallerPolicyDelegateTest, TestNoExistingVersions) {
+  const base::Version testVersion("1.2.3.4");
 
-  std::unique_ptr<base::DictionaryValue> manifest = test_manifest();
-  const int result =
-      mock_policy_->OnCustomInstall(*manifest, GetTestInstallPath()).error;
-  EXPECT_EQ(result, static_cast<int>(update_client::InstallError::NONE));
-
-  EXPECT_EQ(mock_service.GetVersion().GetString(), kTestVersion);
-  EXPECT_EQ(mock_service.GetComponentId(), kComponentId);
+  delegate_->ComponentReady(testVersion, GetTestInstallPath(),
+                            test_manifest(testVersion));
 
   // Check that the original install path still has files.
   AssertTestFiles(GetTestInstallPath());
 
-  // The incoming `install_dir` has to be different from the original one.
-  EXPECT_NE(mock_service.GetNewInstallDir(), GetTestInstallPath());
+  AssertTestFiles(
+      cps_component_path_.AppendASCII("1_" + testVersion.GetString()));
 }
 
-TEST_F(AwComponentInstallerPolicyDelegateTest, TestFailedNotifyNewVersion) {
-  MockAwComponentUpdateService mock_service(/* notify_result= */ false);
-  SetAwComponentUpdateServiceForTesting(&mock_service);
-  CreateTestFiles(GetTestInstallPath());
+TEST_F(AwComponentInstallerPolicyDelegateTest, TestExistingOtherVersions) {
+  const base::Version testVersion("1.2.3.4");
 
-  std::unique_ptr<base::DictionaryValue> manifest = test_manifest();
-  const int result =
-      mock_policy_->OnCustomInstall(*manifest, GetTestInstallPath()).error;
-  EXPECT_EQ(result,
-            static_cast<int>(update_client::InstallError::GENERIC_ERROR));
+  CreateTestFiles(cps_component_path_.AppendASCII("1_4.3.2.1"));
+  CreateTestFiles(cps_component_path_.AppendASCII("10_2.3.4.1"));
+
+  delegate_->ComponentReady(testVersion, GetTestInstallPath(),
+                            test_manifest(testVersion));
+
+  // Check that the original install path still has files.
+  AssertTestFiles(GetTestInstallPath());
+
+  AssertTestFiles(
+      cps_component_path_.AppendASCII("11_" + testVersion.GetString()));
+}
+
+TEST_F(AwComponentInstallerPolicyDelegateTest, TestExistingSameVersion) {
+  const base::Version testVersion("1.2.3.4");
+
+  CreateTestFiles(
+      cps_component_path_.AppendASCII("5_" + testVersion.GetString()));
+
+  delegate_->ComponentReady(testVersion, GetTestInstallPath(),
+                            test_manifest(testVersion));
+
+  // Check that the original install path still has files.
+  AssertTestFiles(GetTestInstallPath());
+
+  // Directory should only contain "<component-id>/5/1.2.3.4/", no other files
+  // or directories should exist.
+  base::FileEnumerator file_enumerator(
+      cps_component_path_, /* recursive= */ false,
+      base::FileEnumerator::DIRECTORIES | base::FileEnumerator::FILES);
+  for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+       path = file_enumerator.Next()) {
+    EXPECT_EQ(path.BaseName().MaybeAsASCII(), "5_" + testVersion.GetString());
+    AssertTestFiles(path);
+  }
 }
 
 }  // namespace android_webview
diff --git a/android_webview/nonembedded/component_updater/aw_component_update_service.cc b/android_webview/nonembedded/component_updater/aw_component_update_service.cc
index 667631d..e5011f0 100644
--- a/android_webview/nonembedded/component_updater/aw_component_update_service.cc
+++ b/android_webview/nonembedded/component_updater/aw_component_update_service.cc
@@ -16,7 +16,6 @@
 #include "base/callback_helpers.h"
 #include "base/check.h"
 #include "base/command_line.h"
-#include "base/files/file_path.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/component_updater/component_installer.h"
 #include "components/component_updater/component_updater_paths.h"
@@ -27,21 +26,8 @@
 
 namespace android_webview {
 
-namespace {
-
-AwComponentUpdateService* g_aw_component_update_service_for_testing = nullptr;
-
-}  // namespace
-
-void SetAwComponentUpdateServiceForTesting(AwComponentUpdateService* service) {
-  g_aw_component_update_service_for_testing = service;
-}
-
 // static
 AwComponentUpdateService* AwComponentUpdateService::GetInstance() {
-  if (g_aw_component_update_service_for_testing) {
-    return g_aw_component_update_service_for_testing;
-  }
   static base::NoDestructor<AwComponentUpdateService> instance;
   return instance.get();
 }
@@ -67,15 +53,6 @@
 
 AwComponentUpdateService::~AwComponentUpdateService() = default;
 
-bool AwComponentUpdateService::NotifyNewVersion(
-    const std::string& component_id,
-    const base::FilePath& install_dir,
-    const base::Version& version) {
-  // TODO(crbug.com/1171771) notify ComponentProviderService about the new
-  // version.
-  return false;
-}
-
 // Start ComponentUpdateService once.
 void AwComponentUpdateService::StartComponentUpdateService(
     base::OnceClosure finished_callback) {
diff --git a/android_webview/nonembedded/component_updater/aw_component_update_service.h b/android_webview/nonembedded/component_updater/aw_component_update_service.h
index e6cd9f6..2bd0aa6 100644
--- a/android_webview/nonembedded/component_updater/aw_component_update_service.h
+++ b/android_webview/nonembedded/component_updater/aw_component_update_service.h
@@ -19,17 +19,11 @@
 #include "base/sequence_checker.h"
 #include "components/update_client/update_client.h"
 
-namespace base {
-class FilePath;
-class Version;
-}  // namespace base
-
 namespace android_webview {
 
 using RegisterComponentsCallback =
     base::RepeatingCallback<bool(const update_client::CrxComponent&)>;
 
-class MockAwComponentUpdateService;
 class TestAwComponentUpdateService;
 
 // Native-side implementation of the AwComponentUpdateService. It
@@ -39,9 +33,6 @@
   static AwComponentUpdateService* GetInstance();
   void StartComponentUpdateService(base::OnceClosure finished_callback);
 
-  virtual bool NotifyNewVersion(const std::string& component_id,
-                                const base::FilePath& install_dir,
-                                const base::Version& version);
   bool RegisterComponent(const update_client::CrxComponent& component);
   void CheckForUpdates(base::OnceClosure on_finished);
 
@@ -49,7 +40,6 @@
   SEQUENCE_CHECKER(sequence_checker_);
 
   friend base::NoDestructor<AwComponentUpdateService>;
-  friend MockAwComponentUpdateService;
   friend TestAwComponentUpdateService;
 
   FRIEND_TEST_ALL_PREFIXES(AwComponentUpdateServiceTest,
@@ -91,8 +81,6 @@
   base::WeakPtrFactory<AwComponentUpdateService> weak_ptr_factory_{this};
 };
 
-void SetAwComponentUpdateServiceForTesting(AwComponentUpdateService* service);
-
 }  // namespace android_webview
 
 #endif  // ANDROID_WEBVIEW_NONEMBEDDED_COMPONENT_UPDATER_AW_COMPONENT_UPDATE_SERVICE_H_
diff --git a/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.cc b/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.cc
index 2c2647b8..199a11d 100644
--- a/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.cc
+++ b/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.cc
@@ -29,13 +29,6 @@
 AwOriginTrialsComponentInstallerPolicy::
     ~AwOriginTrialsComponentInstallerPolicy() = default;
 
-update_client::CrxInstaller::Result
-AwOriginTrialsComponentInstallerPolicy::OnCustomInstall(
-    const base::DictionaryValue& manifest,
-    const base::FilePath& install_dir) {
-  return delegate_->OnCustomInstall(manifest, install_dir);
-}
-
 void AwOriginTrialsComponentInstallerPolicy::OnCustomUninstall() {
   delegate_->OnCustomUninstall();
 }
diff --git a/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.h b/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.h
index 9d390e9e..196f286a 100644
--- a/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.h
+++ b/android_webview/nonembedded/component_updater/installer_policies/aw_origin_trials_component_installer.h
@@ -32,9 +32,6 @@
   AwOriginTrialsComponentInstallerPolicy& operator=(
       const AwOriginTrialsComponentInstallerPolicy&) = delete;
 
-  update_client::CrxInstaller::Result OnCustomInstall(
-      const base::DictionaryValue& manifest,
-      const base::FilePath& install_dir) override;
   void OnCustomUninstall() override;
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
diff --git a/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.cc b/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.cc
index fe2d9d0..7d8be93 100644
--- a/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.cc
+++ b/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.cc
@@ -34,15 +34,10 @@
 AwTrustTokenKeyCommitmentsComponentInstallerPolicy::
     ~AwTrustTokenKeyCommitmentsComponentInstallerPolicy() = default;
 
-update_client::CrxInstaller::Result
-AwTrustTokenKeyCommitmentsComponentInstallerPolicy::OnCustomInstall(
-    const base::DictionaryValue& manifest,
-    const base::FilePath& install_dir) {
-  return delegate_->OnCustomInstall(manifest, install_dir);
-}
 void AwTrustTokenKeyCommitmentsComponentInstallerPolicy::OnCustomUninstall() {
   delegate_->OnCustomUninstall();
 }
+
 void AwTrustTokenKeyCommitmentsComponentInstallerPolicy::ComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.h b/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.h
index ef3f607..f23375ac 100644
--- a/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.h
+++ b/android_webview/nonembedded/component_updater/installer_policies/aw_trust_token_key_commitments_component_installer_policy.h
@@ -38,9 +38,6 @@
   AwTrustTokenKeyCommitmentsComponentInstallerPolicy& operator=(
       const AwTrustTokenKeyCommitmentsComponentInstallerPolicy&) = delete;
 
-  update_client::CrxInstaller::Result OnCustomInstall(
-      const base::DictionaryValue& manifest,
-      const base::FilePath& install_dir) override;
   void OnCustomUninstall() override;
   void ComponentReady(const base::Version& version,
                       const base::FilePath& install_dir,
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 63f012a4..8d3a7bb 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -23,10 +23,7 @@
 python_library("webview_cts_tests") {
   pydeps_file = "//android_webview/tools/run_cts.pydeps"
   deps = [ "//android_webview:system_webview_apk" ]
-  data_deps = [
-    "//build/android:test_runner_py",
-    "//testing/buildbot/filters:webview_cts_tests_filters",
-  ]
+  data_deps = [ "//build/android:test_runner_py" ]
   data = [ "//android_webview/tools/cts_config/" ]
 }
 
diff --git a/apps/ui/views/app_window_frame_view.cc b/apps/ui/views/app_window_frame_view.cc
index 1a73ae21..f96d7be 100644
--- a/apps/ui/views/app_window_frame_view.cc
+++ b/apps/ui/views/app_window_frame_view.cc
@@ -249,8 +249,11 @@
 }
 
 void AppWindowFrameView::Layout() {
+  NonClientFrameView::Layout();
+
   if (!draw_frame_)
     return;
+
   gfx::Size close_size = close_button_->GetPreferredSize();
   const int kButtonOffsetY = 0;
   const int kButtonSpacing = 1;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0b99149..3e140de0 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -110,8 +110,6 @@
   sources = [
     "accelerators/accelerator_commands.cc",
     "accelerators/accelerator_commands.h",
-    "accelerators/accelerator_confirmation_dialog.cc",
-    "accelerators/accelerator_confirmation_dialog.h",
     "accelerators/accelerator_controller_impl.cc",
     "accelerators/accelerator_controller_impl.h",
     "accelerators/accelerator_history_impl.cc",
@@ -140,6 +138,8 @@
     "accelerometer/accelerometer_reader.h",
     "accelerometer/accelerometer_types.cc",
     "accelerometer/accelerometer_types.h",
+    "accessibility/accessibility_confirmation_dialog.cc",
+    "accessibility/accessibility_confirmation_dialog.h",
     "accessibility/accessibility_controller_impl.cc",
     "accessibility/accessibility_cursor_ring_layer.cc",
     "accessibility/accessibility_cursor_ring_layer.h",
@@ -2624,6 +2624,7 @@
   public = [
     "public/cpp/holding_space/holding_space_test_api.h",
     "public/cpp/test/accessibility_controller_test_api.h",
+    "public/cpp/test/app_list_test_api.h",
     "public/cpp/test/assistant_test_api.h",
   ]
   sources = [
@@ -2694,7 +2695,6 @@
     "projector/test/mock_projector_metadata_controller.h",
     "projector/test/mock_projector_ui_controller.cc",
     "projector/test/mock_projector_ui_controller.h",
-    "public/cpp/test/app_list_test_api.h",
     "public/cpp/test/shell_test_api.h",
     "rotator/screen_rotation_animator_test_api.cc",
     "rotator/screen_rotation_animator_test_api.h",
diff --git a/ash/accelerators/accelerator_confirmation_dialog.h b/ash/accelerators/accelerator_confirmation_dialog.h
deleted file mode 100644
index 38229e3..0000000
--- a/ash/accelerators/accelerator_confirmation_dialog.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (c) 2018 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 ASH_ACCELERATORS_ACCELERATOR_CONFIRMATION_DIALOG_H_
-#define ASH_ACCELERATORS_ACCELERATOR_CONFIRMATION_DIALOG_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "ui/views/window/dialog_delegate.h"
-
-namespace ash {
-
-// Defines a dialog for accelerators that require confirmation from users prior
-// to perform.
-class AcceleratorConfirmationDialog : public views::DialogDelegateView {
- public:
-  AcceleratorConfirmationDialog(int window_title_text_id,
-                                int dialog_text_id,
-                                base::OnceClosure on_accept_callback,
-                                base::OnceClosure on_cancel_callback);
-  ~AcceleratorConfirmationDialog() override;
-
-  base::WeakPtr<AcceleratorConfirmationDialog> GetWeakPtr();
-
- private:
-  base::WeakPtrFactory<AcceleratorConfirmationDialog> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(AcceleratorConfirmationDialog);
-};
-
-}  // namespace ash
-
-#endif  // ASH_ACCELERATORS_ACCELERATOR_CONFIRMATION_DIALOG_H_
diff --git a/ash/accelerators/accelerator_controller_impl.cc b/ash/accelerators/accelerator_controller_impl.cc
index 9241cf2..c1999dd 100644
--- a/ash/accelerators/accelerator_controller_impl.cc
+++ b/ash/accelerators/accelerator_controller_impl.cc
@@ -10,8 +10,8 @@
 #include <utility>
 
 #include "ash/accelerators/accelerator_commands.h"
-#include "ash/accelerators/accelerator_confirmation_dialog.h"
 #include "ash/accelerators/debug_commands.h"
+#include "ash/accessibility/accessibility_confirmation_dialog.h"
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/ambient/ambient_controller.h"
 #include "ash/app_list/app_list_controller_impl.h"
@@ -1666,7 +1666,7 @@
   return it->second;
 }
 
-AcceleratorConfirmationDialog*
+AccessibilityConfirmationDialog*
 AcceleratorControllerImpl::TestApi::GetConfirmationDialog() {
   return controller_->confirmation_dialog_.get();
 }
@@ -2578,9 +2578,10 @@
   if (confirmation_dialog_)
     return;
 
-  auto* dialog = new AcceleratorConfirmationDialog(
-      window_title_text_id, dialog_text_id, std::move(on_accept_callback),
-      std::move(on_cancel_callback));
+  auto* dialog = new AccessibilityConfirmationDialog(
+      l10n_util::GetStringUTF16(window_title_text_id),
+      l10n_util::GetStringUTF16(dialog_text_id), std::move(on_accept_callback),
+      std::move(on_cancel_callback), /* on close */ base::DoNothing());
   confirmation_dialog_ = dialog->GetWeakPtr();
 }
 
diff --git a/ash/accelerators/accelerator_controller_impl.h b/ash/accelerators/accelerator_controller_impl.h
index 2f0fddd..841a11da 100644
--- a/ash/accelerators/accelerator_controller_impl.h
+++ b/ash/accelerators/accelerator_controller_impl.h
@@ -12,10 +12,10 @@
 #include <set>
 #include <vector>
 
-#include "ash/accelerators/accelerator_confirmation_dialog.h"
 #include "ash/accelerators/accelerator_history_impl.h"
 #include "ash/accelerators/accelerator_table.h"
 #include "ash/accelerators/exit_warning_handler.h"
+#include "ash/accessibility/accessibility_confirmation_dialog.h"
 #include "ash/ash_export.h"
 #include "ash/public/cpp/accelerators.h"
 #include "base/compiler_specific.h"
@@ -112,7 +112,7 @@
         AcceleratorAction action);
 
     // Accessor to accelerator confirmation dialog.
-    AcceleratorConfirmationDialog* GetConfirmationDialog();
+    AccessibilityConfirmationDialog* GetConfirmationDialog();
 
     AcceleratorControllerImpl::SideVolumeButtonLocation
     side_volume_button_location() {
@@ -334,8 +334,8 @@
   // Actions that can be performed without closing the menu (if one is present).
   std::set<int> actions_keeping_menu_open_;
 
-  // Holds a weak pointer to the accelerator confirmation dialog.
-  base::WeakPtr<AcceleratorConfirmationDialog> confirmation_dialog_;
+  // Holds a weak pointer to the accessibility confirmation dialog.
+  base::WeakPtr<AccessibilityConfirmationDialog> confirmation_dialog_;
 
   // Path of the file that contains the side volume button location info. It
   // should always be kSideVolumeButtonLocationFilePath. But it is allowed to be
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 1518c34..728a94a 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
-#include "ash/accelerators/accelerator_confirmation_dialog.h"
 #include "ash/accelerators/accelerator_history_impl.h"
 #include "ash/accelerators/accelerator_table.h"
 #include "ash/accelerators/pre_target_accelerator_handler.h"
+#include "ash/accessibility/accessibility_confirmation_dialog.h"
 #include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/accessibility/test_accessibility_controller_client.h"
 #include "ash/app_list/app_list_metrics.h"
diff --git a/ash/accelerators/accelerator_confirmation_dialog.cc b/ash/accessibility/accessibility_confirmation_dialog.cc
similarity index 75%
rename from ash/accelerators/accelerator_confirmation_dialog.cc
rename to ash/accessibility/accessibility_confirmation_dialog.cc
index 9e6aa14..f58cd9f0 100644
--- a/ash/accelerators/accelerator_confirmation_dialog.cc
+++ b/ash/accessibility/accessibility_confirmation_dialog.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 "ash/accelerators/accelerator_confirmation_dialog.h"
+#include "ash/accessibility/accessibility_confirmation_dialog.h"
 
 #include <memory>
 #include <utility>
@@ -22,24 +22,25 @@
 
 namespace ash {
 
-AcceleratorConfirmationDialog::AcceleratorConfirmationDialog(
-    int window_title_text_id,
-    int dialog_text_id,
+AccessibilityConfirmationDialog::AccessibilityConfirmationDialog(
+    const std::u16string& window_title_text,
+    const std::u16string& dialog_text,
     base::OnceClosure on_accept_callback,
-    base::OnceClosure on_cancel_callback) {
+    base::OnceClosure on_cancel_callback,
+    base::OnceClosure on_close_callback) {
   SetModalType(ui::MODAL_TYPE_SYSTEM);
-  SetTitle(l10n_util::GetStringUTF16(window_title_text_id));
+  SetTitle(window_title_text);
   SetButtonLabel(ui::DIALOG_BUTTON_OK,
                  l10n_util::GetStringUTF16(IDS_ASH_CONTINUE_BUTTON));
   SetAcceptCallback(std::move(on_accept_callback));
   SetCancelCallback(std::move(on_cancel_callback));
+  SetCloseCallback(std::move(on_close_callback));
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
   SetBorder(views::CreateEmptyBorder(
       views::LayoutProvider::Get()->GetDialogInsetsForContentType(
           views::TEXT, views::TEXT)));
-  AddChildView(std::make_unique<views::Label>(
-      l10n_util::GetStringUTF16(dialog_text_id)));
+  AddChildView(std::make_unique<views::Label>(dialog_text));
 
   // Parent the dialog widget to the LockSystemModalContainer to ensure that it
   // will get displayed on respective lock/signin or OOBE screen.
@@ -58,10 +59,10 @@
   widget->Show();
 }
 
-AcceleratorConfirmationDialog::~AcceleratorConfirmationDialog() = default;
+AccessibilityConfirmationDialog::~AccessibilityConfirmationDialog() = default;
 
-base::WeakPtr<AcceleratorConfirmationDialog>
-AcceleratorConfirmationDialog::GetWeakPtr() {
+base::WeakPtr<AccessibilityConfirmationDialog>
+AccessibilityConfirmationDialog::GetWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
 }
 
diff --git a/ash/accessibility/accessibility_confirmation_dialog.h b/ash/accessibility/accessibility_confirmation_dialog.h
new file mode 100644
index 0000000..6156c54
--- /dev/null
+++ b/ash/accessibility/accessibility_confirmation_dialog.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2018 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 ASH_ACCESSIBILITY_ACCESSIBILITY_CONFIRMATION_DIALOG_H_
+#define ASH_ACCESSIBILITY_ACCESSIBILITY_CONFIRMATION_DIALOG_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace ash {
+
+// Defines a dialog for accessibility that require confirmation from users prior
+// to performing some action.
+class AccessibilityConfirmationDialog : public views::DialogDelegateView {
+ public:
+  AccessibilityConfirmationDialog(const std::u16string& window_title_text,
+                                  const std::u16string& dialog_text,
+                                  base::OnceClosure on_accept_callback,
+                                  base::OnceClosure on_cancel_callback,
+                                  base::OnceClosure on_close_callback);
+  ~AccessibilityConfirmationDialog() override;
+  AccessibilityConfirmationDialog(const AccessibilityConfirmationDialog&) =
+      delete;
+  AccessibilityConfirmationDialog& operator=(
+      const AccessibilityConfirmationDialog&) = delete;
+
+  base::WeakPtr<AccessibilityConfirmationDialog> GetWeakPtr();
+
+ private:
+  base::WeakPtrFactory<AccessibilityConfirmationDialog> weak_ptr_factory_{this};
+};
+
+}  // namespace ash
+
+#endif  // ASH_ACCESSIBILITY_ACCESSIBILITY_CONFIRMATION_DIALOG_H_
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index 14560ea6..0328426f 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -1929,6 +1929,28 @@
   enable_chromevox_volume_slide_gesture_ = true;
 }
 
+void AccessibilityControllerImpl::ShowConfirmationDialog(
+    const std::u16string& title,
+    const std::u16string& description,
+    base::OnceClosure on_accept_callback,
+    base::OnceClosure on_cancel_callback,
+    base::OnceClosure on_close_callback) {
+  if (confirmation_dialog_) {
+    // If a dialog is already being shown we do not show a new one.
+    // Instead, run the on_close_callback on the new dialog to indicate
+    // it was closed without the user taking any action.
+    // This is consistent with AcceleratorController.
+    std::move(on_close_callback).Run();
+    return;
+  }
+  auto* dialog = new AccessibilityConfirmationDialog(
+      title, description, std::move(on_accept_callback),
+      std::move(on_cancel_callback), std::move(on_close_callback));
+  // Save the dialog so it doesn't go out of scope before it is
+  // used and closed.
+  confirmation_dialog_ = dialog->GetWeakPtr();
+}
+
 void AccessibilityControllerImpl::UpdateFeatureFromPref(FeatureType feature) {
   bool enabled = features_[feature]->enabled();
 
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index 4d2ae0e..8157f479 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -40,6 +40,7 @@
 
 namespace ash {
 
+class AccessibilityConfirmationDialog;
 class AccessibilityEventRewriter;
 class AccessibilityHighlightController;
 class AccessibilityObserver;
@@ -390,6 +391,11 @@
   void DisablePolicyRecommendationRestorerForTesting() override;
   void SuspendSwitchAccessKeyHandling(bool suspend) override;
   void EnableChromeVoxVolumeSlideGesture() override;
+  void ShowConfirmationDialog(const std::u16string& title,
+                              const std::u16string& description,
+                              base::OnceClosure on_accept_callback,
+                              base::OnceClosure on_cancel_callback,
+                              base::OnceClosure on_close_callback) override;
 
   // SessionObserver:
   void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override;
@@ -405,6 +411,9 @@
   GetSelectToSpeakMenuBubbleControllerForTest() {
     return select_to_speak_bubble_controller_.get();
   }
+  AccessibilityConfirmationDialog* GetConfirmationDialogForTest() {
+    return confirmation_dialog_.get();
+  }
 
   bool enable_chromevox_volume_slide_gesture() {
     return enable_chromevox_volume_slide_gesture_;
@@ -514,6 +523,9 @@
   // any prefs during destruction.
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
 
+  // The current AccessibilityConfirmationDialog, if one exists.
+  base::WeakPtr<AccessibilityConfirmationDialog> confirmation_dialog_;
+
   base::WeakPtrFactory<AccessibilityControllerImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(AccessibilityControllerImpl);
diff --git a/ash/app_list/app_list_test_api.cc b/ash/app_list/app_list_test_api.cc
index d4d2dd1..a6ba651a 100644
--- a/ash/app_list/app_list_test_api.cc
+++ b/ash/app_list/app_list_test_api.cc
@@ -22,6 +22,10 @@
 AppListTestApi::AppListTestApi() = default;
 AppListTestApi::~AppListTestApi() = default;
 
+bool AppListTestApi::HasApp(const std::string& app_id) {
+  return Shell::Get()->app_list_controller()->GetModel()->FindItem(app_id);
+}
+
 std::vector<std::string> AppListTestApi::GetTopLevelViewIdList() {
   std::vector<std::string> id_list;
   AppListView* app_list_view =
diff --git a/ash/app_list/views/search_box_view_unittest.cc b/ash/app_list/views/search_box_view_unittest.cc
index 60b318a..96f7c492 100644
--- a/ash/app_list/views/search_box_view_unittest.cc
+++ b/ash/app_list/views/search_box_view_unittest.cc
@@ -91,9 +91,9 @@
   }
 
   void TearDown() override {
-    view_.reset();
     app_list_view_->GetWidget()->Close();
     widget_->CloseNow();
+    view_.reset();
     views::test::WidgetTest::TearDown();
   }
 
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index 7d6f191..c48ba52 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -199,10 +199,6 @@
 const base::Feature kCrostiniGpuSupport{"CrostiniGpuSupport",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables or disables the new WebUI Crostini upgrader.
-const base::Feature kCrostiniWebUIUpgrader{"CrostiniWebUIUpgrader",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Use DLC instead of component updater for managing the Termina image if set
 // (and component updater instead of DLC if not).
 const base::Feature kCrostiniUseDlc{"CrostiniUseDlc",
@@ -320,10 +316,6 @@
 const base::Feature kFamilyLinkOnSchoolDevice{"FamilyLinkOnSchoolDevice",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables the camera folder handling in files app.
-const base::Feature kFilesCameraFolder{"FilesCameraFolder",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables the next generation file manager.
 const base::Feature kFilesNG{"FilesNG", base::FEATURE_ENABLED_BY_DEFAULT};
 
@@ -617,10 +609,6 @@
 const base::Feature kShowBluetoothDebugLogToggle{
     "ShowBluetoothDebugLogToggle", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables or disables verbose Bluetooth log collection for Googlers.
-const base::Feature kEnableBluetoothVerboseLogsForGooglers{
-    "EnableBluetoothVerboseLogsForGooglers", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Shows the Play Store icon in Demo Mode.
 const base::Feature kShowPlayInDemoMode{"ShowPlayInDemoMode",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index b468ff4..fe6e37d 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -118,8 +118,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kDisableIdleSocketsCloseOnMemoryPressure;
 COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kCrostiniWebUIUpgrader;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCryptAuthV2DeviceSync;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCryptAuthV2Enrollment;
@@ -152,8 +150,6 @@
 extern const base::Feature kExoLockNotification;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kFamilyLinkOnSchoolDevice;
-COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kFilesCameraFolder;
 COMPONENT_EXPORT(ASH_CONSTANTS) extern const base::Feature kFilesJsModules;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kAudioPlayerJsModules;
@@ -284,8 +280,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kShowBluetoothDebugLogToggle;
 COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kEnableBluetoothVerboseLogsForGooglers;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kShowPlayInDemoMode;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kSmartDimExperimentalComponent;
diff --git a/ash/frame/default_frame_header_unittest.cc b/ash/frame/default_frame_header_unittest.cc
index 1299e199..28b5ccf 100644
--- a/ash/frame/default_frame_header_unittest.cc
+++ b/ash/frame/default_frame_header_unittest.cc
@@ -277,7 +277,7 @@
     LayerDestroyedChecker checker(animating_layer);
 
     // Change the view's stacking order should stop the animation.
-    ASSERT_EQ(2u, frame_view_1->children().size());
+    ASSERT_EQ(3u, frame_view_1->children().size());
     frame_view_1->ReorderChildView(extra_view_1, 0);
 
     EXPECT_EQ(
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc
index 1f8a693..5c1bb63 100644
--- a/ash/frame/non_client_frame_view_ash.cc
+++ b/ash/frame/non_client_frame_view_ash.cc
@@ -327,16 +327,16 @@
 }
 
 void NonClientFrameViewAsh::Layout() {
-  if (!GetEnabled())
-    return;
   views::NonClientFrameView::Layout();
+  if (!GetFrameEnabled())
+    return;
   aura::Window* frame_window = frame_->GetNativeWindow();
   frame_window->SetProperty(aura::client::kTopViewInset,
                             NonClientTopBorderHeight());
 }
 
 gfx::Size NonClientFrameViewAsh::GetMinimumSize() const {
-  if (!GetEnabled())
+  if (!GetFrameEnabled())
     return gfx::Size();
 
   gfx::Size min_client_view_size(frame_->client_view()->GetMinimumSize());
@@ -358,13 +358,6 @@
   return gfx::Size(width, height);
 }
 
-void NonClientFrameViewAsh::SetVisible(bool visible) {
-  overlay_view_->SetVisible(visible);
-  views::View::SetVisible(visible);
-  // We need to re-layout so that client view will occupy entire window.
-  InvalidateLayout();
-}
-
 void NonClientFrameViewAsh::SetShouldPaintHeader(bool paint) {
   header_view_->SetShouldPaintHeader(paint);
 }
@@ -372,7 +365,7 @@
 int NonClientFrameViewAsh::NonClientTopBorderHeight() const {
   // The frame should not occupy the window area when it's in fullscreen,
   // not visible or disabled.
-  if (frame_->IsFullscreen() || !GetVisible() || !GetEnabled() ||
+  if (frame_->IsFullscreen() || !GetFrameEnabled() ||
       header_view_->in_immersive_mode()) {
     return 0;
   }
@@ -395,6 +388,15 @@
   return frame_->GetNativeWindow()->GetProperty(kFrameInactiveColorKey);
 }
 
+void NonClientFrameViewAsh::SetFrameEnabled(bool enabled) {
+  if (enabled == frame_enabled_)
+    return;
+
+  frame_enabled_ = enabled;
+  overlay_view_->SetVisible(frame_enabled_);
+  InvalidateLayout();
+}
+
 void NonClientFrameViewAsh::OnDidSchedulePaint(const gfx::Rect& r) {
   // We may end up here before |header_view_| has been added to the Widget.
   if (header_view_->GetWidget()) {
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h
index ac2633a..c5efb79 100644
--- a/ash/frame/non_client_frame_view_ash.h
+++ b/ash/frame/non_client_frame_view_ash.h
@@ -90,7 +90,6 @@
   void Layout() override;
   gfx::Size GetMinimumSize() const override;
   gfx::Size GetMaximumSize() const override;
-  void SetVisible(bool visible) override;
 
   // If |paint| is false, we should not paint the header. Used for overview mode
   // with OnOverviewModeStarting() and OnOverviewModeEnded() to hide/show the
@@ -111,6 +110,9 @@
 
   views::Widget* frame() { return frame_; }
 
+  bool GetFrameEnabled() const { return frame_enabled_; }
+  virtual void SetFrameEnabled(bool enabled);
+
  protected:
   // views::View:
   void OnDidSchedulePaint(const gfx::Rect& r) override;
@@ -141,6 +143,8 @@
 
   OverlayView* overlay_view_ = nullptr;
 
+  bool frame_enabled_ = true;
+
   std::unique_ptr<NonClientFrameViewAshImmersiveHelper> immersive_helper_;
 
   base::CallbackListSubscription paint_as_active_subscription_ =
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc
index c73a707..8b1a0259 100644
--- a/ash/frame/non_client_frame_view_ash_unittest.cc
+++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -543,19 +543,19 @@
       delegate->non_client_frame_view();
   EXPECT_EQ(client_bounds, widget->client_view()->GetLocalBounds().size());
 
-  non_client_frame_view->SetVisible(false);
+  non_client_frame_view->SetFrameEnabled(false);
   widget->GetRootView()->Layout();
   EXPECT_EQ(gfx::Size(200, 100),
             widget->client_view()->GetLocalBounds().size());
-  EXPECT_FALSE(widget->non_client_view()->frame_view()->GetVisible());
+  EXPECT_FALSE(non_client_frame_view->GetFrameEnabled());
   EXPECT_EQ(
       window_bounds,
       non_client_frame_view->GetClientBoundsForWindowBounds(window_bounds));
 
-  non_client_frame_view->SetVisible(true);
+  non_client_frame_view->SetFrameEnabled(true);
   widget->GetRootView()->Layout();
   EXPECT_EQ(client_bounds, widget->client_view()->GetLocalBounds().size());
-  EXPECT_TRUE(widget->non_client_view()->frame_view()->GetVisible());
+  EXPECT_TRUE(non_client_frame_view->GetFrameEnabled());
   EXPECT_EQ(32, delegate->GetNonClientFrameViewTopBorderHeight());
   EXPECT_EQ(
       gfx::Rect(gfx::Point(10, 42), client_bounds),
diff --git a/ash/public/cpp/accessibility_controller.h b/ash/public/cpp/accessibility_controller.h
index 8982b82..2a9e9bb 100644
--- a/ash/public/cpp/accessibility_controller.h
+++ b/ash/public/cpp/accessibility_controller.h
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/accelerators.h"
 #include "ash/public/cpp/accessibility_controller_enums.h"
 #include "ash/public/cpp/ash_public_export.h"
+#include "base/callback.h"
 #include "base/macros.h"
 
 namespace gfx {
@@ -147,6 +148,15 @@
   // Enables ChromeVox's volume slide gesture.
   virtual void EnableChromeVoxVolumeSlideGesture() {}
 
+  // Shows a confirmation dialog with the given text and description,
+  // and calls the relevant callback when the dialog is confirmed, canceled
+  // or closed.
+  virtual void ShowConfirmationDialog(const std::u16string& title,
+                                      const std::u16string& description,
+                                      base::OnceClosure on_accept_callback,
+                                      base::OnceClosure on_cancel_callback,
+                                      base::OnceClosure on_close_callback) {}
+
  protected:
   AccessibilityController();
   virtual ~AccessibilityController();
diff --git a/ash/public/cpp/test/app_list_test_api.h b/ash/public/cpp/test/app_list_test_api.h
index b9e521b..52fc34a 100644
--- a/ash/public/cpp/test/app_list_test_api.h
+++ b/ash/public/cpp/test/app_list_test_api.h
@@ -20,6 +20,9 @@
   AppListTestApi(const AppListTestApi& other) = delete;
   AppListTestApi& operator=(const AppListTestApi& other) = delete;
 
+  // Returns whether there is an item for |app_id|.
+  bool HasApp(const std::string& app_id);
+
   // Returns ids of the items in top level app list view.
   std::vector<std::string> GetTopLevelViewIdList();
 
diff --git a/ash/shelf/shelf_test_api.cc b/ash/shelf/shelf_test_api.cc
index 413f813f..e2733ce 100644
--- a/ash/shelf/shelf_test_api.cc
+++ b/ash/shelf/shelf_test_api.cc
@@ -103,9 +103,12 @@
       hotseat_widget->GetNativeView()->layer()->GetAnimator()->is_animating();
   info.hotseat_state = hotseat_widget->state();
 
-  const gfx::Rect shelf_widget_bounds =
-      GetShelf()->shelf_widget()->GetWindowBoundsInScreen();
-  info.swipe_up.swipe_start_location = shelf_widget_bounds.CenterPoint();
+  // Hotseat swipe can happen from the bottom center of the display.
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(
+          hotseat_widget->GetNativeWindow()->GetRootWindow());
+  info.swipe_up.swipe_start_location = gfx::Point(
+      display.bounds().CenterPoint().x(), display.bounds().bottom() - 1);
 
   // The swipe distance is small enough to avoid the window drag from shelf.
   const int swipe_distance = hotseat_widget->GetHotseatFullDragAmount() / 2;
diff --git a/ash/system/holding_space/holding_space_tray_bubble.cc b/ash/system/holding_space/holding_space_tray_bubble.cc
index 9f5ce20a..e54e2fd 100644
--- a/ash/system/holding_space/holding_space_tray_bubble.cc
+++ b/ash/system/holding_space/holding_space_tray_bubble.cc
@@ -319,6 +319,8 @@
 
   // Create and customize bubble view.
   TrayBubbleView* bubble_view = new TrayBubbleView(init_params);
+  // Ensure bubble frame does not draw background behind bubble view.
+  bubble_view->set_color(SK_ColorTRANSPARENT);
   child_bubble_container_ =
       bubble_view->AddChildView(std::make_unique<ChildBubbleContainer>());
   child_bubble_container_->SetMaxHeight(CalculateMaxHeight());
@@ -339,12 +341,6 @@
   bubble_wrapper_ = std::make_unique<TrayBubbleWrapper>(
       holding_space_tray, bubble_view, false /* is_persistent */);
 
-  // Set bubble frame to be invisible.
-  bubble_wrapper_->GetBubbleWidget()
-      ->non_client_view()
-      ->frame_view()
-      ->SetVisible(false);
-
   event_handler_ =
       std::make_unique<HoldingSpaceTrayBubbleEventHandler>(this, &delegate_);
 
diff --git a/ash/system/message_center/unified_message_center_bubble.cc b/ash/system/message_center/unified_message_center_bubble.cc
index 01bcccd..ed49b92e 100644
--- a/ash/system/message_center/unified_message_center_bubble.cc
+++ b/ash/system/message_center/unified_message_center_bubble.cc
@@ -135,6 +135,7 @@
 int UnifiedMessageCenterBubble::CalculateAvailableHeight() {
   return tray_->bubble()->CalculateMaxHeight() -
          tray_->bubble()->GetCurrentTrayHeight() -
+         GetBubbleInsetHotseatCompensation() -
          kUnifiedMessageCenterBubbleSpacing;
 }
 
diff --git a/ash/system/tray/tray_utils.cc b/ash/system/tray/tray_utils.cc
index 1cff46d..51d26fd 100644
--- a/ash/system/tray/tray_utils.cc
+++ b/ash/system/tray/tray_utils.cc
@@ -55,7 +55,15 @@
   if (!is_bottom_alignment)
     return insets;
 
+  int height_compensation = GetBubbleInsetHotseatCompensation();
+  insets.set_bottom(insets.bottom() + height_compensation);
+  return insets;
+}
+
+int GetBubbleInsetHotseatCompensation() {
   int height_compensation = kTrayBubbleInsetHotseatCompensation;
+  Shelf* shelf = Shelf::ForWindow(Shell::GetPrimaryRootWindow());
+
   switch (shelf->GetBackgroundType()) {
     case ShelfBackgroundType::kInApp:
     case ShelfBackgroundType::kOverview:
@@ -70,9 +78,7 @@
     default:
       break;
   }
-
-  insets.set_bottom(insets.bottom() + height_compensation);
-  return insets;
+  return height_compensation;
 }
 
 gfx::Insets GetSecondaryBubbleInsets() {
diff --git a/ash/system/tray/tray_utils.h b/ash/system/tray/tray_utils.h
index 81e414d..dff5a70 100644
--- a/ash/system/tray/tray_utils.h
+++ b/ash/system/tray/tray_utils.h
@@ -24,6 +24,10 @@
 // Returns the insets above the shelf for positioning the quick settings bubble.
 gfx::Insets GetTrayBubbleInsets();
 
+// Calculates the height compensations in tablet mode based on whether the
+// hotseat is shown.
+int GetBubbleInsetHotseatCompensation();
+
 // Returns the separation above the shelf for positioning secondary tray
 // bubbles. (Palette Tray, IME Tray).
 gfx::Insets GetSecondaryBubbleInsets();
diff --git a/ash/wm/desks/desk_drag_proxy.cc b/ash/wm/desks/desk_drag_proxy.cc
index 0eb56c6..21f4559 100644
--- a/ash/wm/desks/desk_drag_proxy.cc
+++ b/ash/wm/desks/desk_drag_proxy.cc
@@ -32,11 +32,12 @@
 
 DeskDragProxy::DeskDragProxy(DesksBarView* desks_bar_view,
                              DeskMiniView* drag_view,
-                             const gfx::Vector2dF& init_offset)
+                             float init_offset_x)
     : desks_bar_view_(desks_bar_view),
       drag_view_(drag_view),
       drag_preview_size_(drag_view->GetPreviewBoundsInScreen().size()),
-      init_offset_(init_offset) {}
+      preview_screen_y_(drag_view->GetPreviewBoundsInScreen().y()),
+      init_offset_x_(init_offset_x) {}
 
 DeskDragProxy::~DeskDragProxy() = default;
 
@@ -53,8 +54,7 @@
   return drag_widget_->GetWindowBoundsInScreen().origin();
 }
 
-void DeskDragProxy::InitAndScaleAndMoveTo(
-    const gfx::PointF& location_in_screen) {
+void DeskDragProxy::InitAndScaleAndMoveToX(float location_screen_x) {
   DCHECK(drag_view_);
 
   aura::Window* root_window =
@@ -88,14 +88,15 @@
       scale_transform));
 
   // Perform Moving.
-  DragTo(location_in_screen);
+  DragToX(location_screen_x);
 
   state_ = State::kStarted;
 }
 
-void DeskDragProxy::DragTo(const gfx::PointF& location_in_screen) {
+void DeskDragProxy::DragToX(float location_screen_x) {
   drag_widget_->SetBounds(
-      gfx::Rect(gfx::ToRoundedPoint(location_in_screen - init_offset_),
+      gfx::Rect(gfx::Point(base::ClampRound(location_screen_x - init_offset_x_),
+                           preview_screen_y_),
                 drag_preview_size_));
 }
 
diff --git a/ash/wm/desks/desk_drag_proxy.h b/ash/wm/desks/desk_drag_proxy.h
index ba43fddc..88238a7c 100644
--- a/ash/wm/desks/desk_drag_proxy.h
+++ b/ash/wm/desks/desk_drag_proxy.h
@@ -38,7 +38,7 @@
 
   DeskDragProxy(DesksBarView* desks_bar_view,
                 DeskMiniView* drag_view,
-                const gfx::Vector2dF& init_offset);
+                float init_offset_x);
   DeskDragProxy(const DeskDragProxy&) = delete;
   DeskDragProxy& operator=(const DeskDragProxy&) = delete;
   ~DeskDragProxy() override;
@@ -48,12 +48,12 @@
 
   gfx::Point GetPositionInScreen() const;
 
-  // Drag is started. Create a drag proxy widget, scale it up and move it to
-  // |location_in_screen|.
-  void InitAndScaleAndMoveTo(const gfx::PointF& location_in_screen);
+  // Drag is started. Create a drag proxy widget, scale it up and move its
+  // x-coordinate according to |location_screen_x|.
+  void InitAndScaleAndMoveToX(float location_screen_x);
 
-  // Move drag proxy to |location_in_screen|.
-  void DragTo(const gfx::PointF& location_in_screen);
+  // Move drag proxy's x-coordinate according to |location_screen_x|.
+  void DragToX(float location_screen_x);
 
   // Perform and animate snapping back to drag view.
   void SnapBackToDragView();
@@ -66,8 +66,10 @@
   DeskMiniView* drag_view_ = nullptr;
   // The size of dragged preview.
   const gfx::Size drag_preview_size_;
-  // The initial offset between cursor and drag view's origin.
-  gfx::Vector2dF init_offset_;
+  // The y of the dragged preview in screen coordinate.
+  const int preview_screen_y_;
+  // The x of initial offset between cursor and drag view's origin.
+  const float init_offset_x_;
   // The widget of drag proxy.
   views::UniqueWidgetPtr drag_widget_;
   // The state of the drag proxy.
diff --git a/ash/wm/desks/desks_bar_view.cc b/ash/wm/desks/desks_bar_view.cc
index 7b2a171..60ada2a 100644
--- a/ash/wm/desks/desks_bar_view.cc
+++ b/ash/wm/desks/desks_bar_view.cc
@@ -632,12 +632,12 @@
 
   gfx::PointF preview_origin_in_screen(
       drag_view_->GetPreviewBoundsInScreen().origin());
-  gfx::Vector2dF drag_origin_offset =
-      location_in_screen - preview_origin_in_screen;
+  const float init_offset_x =
+      location_in_screen.x() - preview_origin_in_screen.x();
 
   // Create a drag proxy for the dragged desk.
   drag_proxy_ =
-      std::make_unique<DeskDragProxy>(this, drag_view_, drag_origin_offset);
+      std::make_unique<DeskDragProxy>(this, drag_view_, init_offset_x);
 }
 
 void DesksBarView::StartDragDesk(DeskMiniView* mini_view,
@@ -649,9 +649,9 @@
   // Hide the dragged mini view.
   drag_view_->layer()->SetOpacity(0.0f);
 
-  // Create a drag proxy widget, scale it up and move it to the
-  // |location_in_screen|.
-  drag_proxy_->InitAndScaleAndMoveTo(location_in_screen);
+  // Create a drag proxy widget, scale it up and move its x-coordinate according
+  // to the x of |location_in_screen|.
+  drag_proxy_->InitAndScaleAndMoveToX(location_in_screen.x());
 
   Shell::Get()->cursor_manager()->SetCursor(ui::mojom::CursorType::kGrabbing);
 }
@@ -662,7 +662,7 @@
   DCHECK(drag_proxy_);
   DCHECK_EQ(mini_view, drag_view_);
 
-  drag_proxy_->DragTo(location_in_screen);
+  drag_proxy_->DragToX(location_in_screen.x());
 
   const auto drag_view_iter =
       std::find(mini_views_.cbegin(), mini_views_.cend(), drag_view_);
@@ -671,16 +671,9 @@
   int old_index = drag_view_iter - mini_views_.cbegin();
 
   gfx::Point drag_pos_in_screen = drag_proxy_->GetPositionInScreen();
-  gfx::Rect bar_bounds = scroll_view_contents_->GetBoundsInScreen();
-  float cursor_y = location_in_screen.y();
 
-  // Determine the target location for the desk to be reordered. If the cursor
-  // is outside the desks bar, then the dragged desk will be moved to the end.
-  // Otherwise, the position is determined by the drag proxy's location.
-  int new_index =
-      (cursor_y < bar_bounds.origin().y() || cursor_y > bar_bounds.bottom())
-          ? (GetMirrored() ? 0 : mini_views_.size() - 1)
-          : DetermineMoveIndex(drag_pos_in_screen.x());
+  // Determine the target location for the desk to be reordered.
+  int new_index = DetermineMoveIndex(drag_pos_in_screen.x());
 
   if (old_index != new_index)
     Shell::Get()->desks_controller()->ReorderDesk(old_index, new_index);
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index ac49290..78d2bed 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -4781,19 +4781,6 @@
   EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
   VerifyDesksRestoreData(prefs, std::vector<std::string>{"1", "0", "2"});
 
-  // If the cursor is outside the desk bar, the second desk will be moved to the
-  // end.
-  gfx::Point desk_bar_bottom_center = desks_bar_view->bounds().bottom_center();
-  views::View::ConvertPointToScreen(desks_bar_view->parent(),
-                                    &desk_bar_bottom_center);
-  event_generator->MoveMouseTo(desk_bar_bottom_center + gfx::Vector2d(0, 10));
-
-  // Now, the desks order should be [0, 2, 1]:
-  EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
-  EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
-  EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
-  VerifyDesksRestoreData(prefs, std::vector<std::string>{"0", "2", "1"});
-
   event_generator->ReleaseLeftButton();
 }
 
@@ -4865,19 +4852,6 @@
   EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_2));
   VerifyDesksRestoreData(prefs, std::vector<std::string>{"1", "0", "2"});
 
-  // If the touch point is outside the desk bar, the second desk will be moved
-  // to the end.
-  gfx::Point desk_bar_bottom_center = desks_bar_view->bounds().bottom_center();
-  views::View::ConvertPointToScreen(desks_bar_view->parent(),
-                                    &desk_bar_bottom_center);
-  event_generator->MoveTouch(desk_bar_bottom_center + gfx::Vector2d(0, 10));
-
-  // Now, the desks order should be [0, 2, 1]:
-  EXPECT_EQ(0, desks_controller->GetDeskIndex(desk_0));
-  EXPECT_EQ(1, desks_controller->GetDeskIndex(desk_2));
-  EXPECT_EQ(2, desks_controller->GetDeskIndex(desk_1));
-  VerifyDesksRestoreData(prefs, std::vector<std::string>{"0", "2", "1"});
-
   event_generator->ReleaseTouch();
 }
 
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc
index 1723e7e..e8a5f8d 100644
--- a/ash/wm/system_modal_container_layout_manager_unittest.cc
+++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -547,11 +547,12 @@
 TEST_F(SystemModalContainerLayoutManagerTest, ChangeCapture) {
   std::unique_ptr<aura::Window> widget_window(ShowToplevelTestWindow(false));
   views::test::CaptureTrackingView* view = new views::test::CaptureTrackingView;
-  views::View* contents_view =
+  views::View* client_view =
       views::Widget::GetWidgetForNativeView(widget_window.get())
-          ->GetContentsView();
-  contents_view->AddChildView(view);
-  view->SetBoundsRect(contents_view->bounds());
+          ->non_client_view()
+          ->client_view();
+  client_view->AddChildView(view);
+  view->SetBoundsRect(client_view->bounds());
 
   gfx::Point center(view->width() / 2, view->height() / 2);
   views::View::ConvertPointToScreen(view, &center);
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index afa98fa..0ca7070 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -144,12 +144,20 @@
 #else
   // Since the general-purpose allocator uses the thread cache, this one cannot.
   static base::NoDestructor<base::ThreadSafePartitionRoot> aligned_allocator(
-      base::PartitionOptions{base::PartitionOptions::Alignment::kAlignedAlloc,
-                             base::PartitionOptions::ThreadCache::kDisabled,
-                             base::PartitionOptions::Quarantine::kAllowed,
-                             base::PartitionOptions::RefCount::kDisabled});
-  return aligned_allocator.get();
+      base::PartitionOptions {
+        base::PartitionOptions::Alignment::kAlignedAlloc,
+            base::PartitionOptions::ThreadCache::kDisabled,
+            base::PartitionOptions::Quarantine::kAllowed,
+#if BUILDFLAG(REF_COUNT_AT_END_OF_ALLOCATION)
+            // Given the outer #if, this is possible only when DCHECK_IS_ON().
+            base::PartitionOptions::RefCount::kEnabled
+#else
+            base::PartitionOptions::RefCount::kDisabled
 #endif
+      });
+  return aligned_allocator.get();
+#endif  // !DCHECK_IS_ON() && (!BUILDFLAG(USE_BACKUP_REF_PTR) ||
+        //                     BUILDFLAG(REF_COUNT_AT_END_OF_ALLOCATION))
 }
 
 #if defined(OS_WIN) && defined(ARCH_CPU_X86)
diff --git a/base/allocator/partition_allocator/partition_ref_count.cc b/base/allocator/partition_allocator/partition_ref_count.cc
index dd9f23b..3c458cc 100644
--- a/base/allocator/partition_allocator/partition_ref_count.cc
+++ b/base/allocator/partition_allocator/partition_ref_count.cc
@@ -38,9 +38,11 @@
   // reserved). Instead, refcount is stored in the subsequent page metadata.
 
   auto* slot_span = SlotSpanMetadata<ThreadSafe>::FromSlotStartPtr(slot_start);
-  PA_DCHECK(slot_span);
 #if DCHECK_IS_ON()
-  PartitionCookieCheckValue(slot_start);
+  PA_DCHECK(slot_span);
+  auto* root = PartitionRoot<ThreadSafe>::FromSlotSpan(slot_span);
+  if (root->allow_cookies)
+    PartitionCookieCheckValue(slot_start);
 #endif
   uint8_t* partition_ref_count_ptr;
   if (UNLIKELY(slot_span->CanStoreRawSize())) {
diff --git a/base/allocator/partition_allocator/partition_root.cc b/base/allocator/partition_allocator/partition_root.cc
index 8547e80..b6e530f 100644
--- a/base/allocator/partition_allocator/partition_root.cc
+++ b/base/allocator/partition_allocator/partition_root.cc
@@ -477,24 +477,14 @@
       internal::PartitionAddressSpace::Init();
 #endif
 
-    // If alignment needs to be enforced, disallow adding a cookie and/or
-    // ref-count at the beginning of the slot.
-    if (opts.alignment == PartitionOptions::Alignment::kAlignedAlloc) {
-      allow_cookies = false;
-      allow_ref_count = false;
-      // There should be no configuration where aligned root and ref-count are
-      // requested at the same time. In theory REF_COUNT_AT_END_OF_ALLOCATION
-      // allows these to co-exist, but in this case aligned root is not even
-      // created.
-      PA_CHECK(opts.ref_count == PartitionOptions::RefCount::kDisabled);
-    } else {
-      allow_cookies = true;
-      // Allow ref-count if it's explicitly requested *and* GigaCage is enabled.
-      // Without GigaCage it'd be unused, thus wasteful.
-      allow_ref_count =
-          (opts.ref_count == PartitionOptions::RefCount::kEnabled) &&
-          features::IsPartitionAllocGigaCageEnabled();
-    }
+    // If alignment needs to be enforced, disallow adding a cookie.
+    allow_cookies =
+        opts.alignment != PartitionOptions::Alignment::kAlignedAlloc;
+    // Allow ref-count if it's explicitly requested *and* GigaCage is enabled.
+    // Without GigaCage it'd be unused, thus wasteful.
+    allow_ref_count =
+        (opts.ref_count == PartitionOptions::RefCount::kEnabled) &&
+        features::IsPartitionAllocGigaCageEnabled();
 
 #if PARTITION_EXTRAS_REQUIRED
     extras_size = 0;
@@ -514,6 +504,10 @@
     }
 #endif
 
+    // Partitions that allow AlignedAlloc can't have pre-allocation extras.
+    PA_CHECK(opts.alignment != PartitionOptions::Alignment::kAlignedAlloc ||
+             !extras_offset);
+
     quarantine_mode =
 #if PA_ALLOW_PCSCAN
         (opts.quarantine == PartitionOptions::Quarantine::kDisallowed
diff --git a/build/android/gyp/dex.py b/build/android/gyp/dex.py
index e160cbda..9bb9e845 100755
--- a/build/android/gyp/dex.py
+++ b/build/android/gyp/dex.py
@@ -112,6 +112,10 @@
   parser.add_argument('--warnings-as-errors',
                       action='store_true',
                       help='Treat all warnings as errors.')
+  parser.add_argument('--dump-inputs',
+                      action='store_true',
+                      help='Use when filing D8 bugs to capture inputs.'
+                      ' Stores inputs to d8inputs.zip')
 
   group = parser.add_argument_group('Dexlayout')
   group.add_argument(
@@ -571,7 +575,12 @@
     final_dex_inputs = list(options.class_inputs)
   final_dex_inputs += options.dex_inputs
 
-  dex_cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
+  dex_cmd = build_utils.JavaCmd(options.warnings_as_errors)
+
+  if options.dump_inputs:
+    dex_cmd += ['-Dcom.android.tools.r8.dumpinputtofile=d8inputs.zip']
+
+  dex_cmd += [
       '-cp',
       '{}:{}'.format(options.r8_jar_path, options.custom_d8_jar_path),
       'org.chromium.build.CustomD8',
diff --git a/build/fuchsia/OWNERS b/build/fuchsia/OWNERS
index f288111..3dcaf8a 100644
--- a/build/fuchsia/OWNERS
+++ b/build/fuchsia/OWNERS
@@ -3,3 +3,6 @@
 kmarshall@chromium.org
 sergeyu@chromium.org
 wez@chromium.org
+
+per-file linux.sdk.sha1=chromium-autoroll@skia-public.iam.gserviceaccount.com
+per-file mac.sdk.sha1=chromium-autoroll@skia-public.iam.gserviceaccount.com
diff --git a/build/fuchsia/aemu_target.py b/build/fuchsia/aemu_target.py
index f9fc6af..85c8c200 100644
--- a/build/fuchsia/aemu_target.py
+++ b/build/fuchsia/aemu_target.py
@@ -41,6 +41,13 @@
     self._hardware_gpu = hardware_gpu
 
   @staticmethod
+  def CreateFromArgs(args):
+    return AemuTarget(args.out_dir, args.target_cpu, args.system_log_file,
+                      args.cpu_cores, args.require_kvm, args.ram_size_mb,
+                      args.enable_graphics, args.hardware_gpu,
+                      args.fuchsia_out_dir)
+
+  @staticmethod
   def RegisterArgs(arg_parser):
     emu_target.EmuTarget.RegisterArgs(arg_parser)
     aemu_args = arg_parser.add_argument_group('aemu', 'AEMU Arguments')
diff --git a/build/fuchsia/binary_sizes.py b/build/fuchsia/binary_sizes.py
index 3792fcd..eb259846 100755
--- a/build/fuchsia/binary_sizes.py
+++ b/build/fuchsia/binary_sizes.py
@@ -251,20 +251,6 @@
   return blob_name_hashes
 
 
-def CommitPositionFromBuildProperty(value):
-  """Extracts the chromium commit position from a builders got_revision_cp
-  property."""
-
-  # Match a commit position from a build properties commit string like
-  # "refs/heads/master@{#819458}"
-  test_arg_commit_position_re = r'\{#(?P<position>\d+)\}'
-
-  match = re.search(test_arg_commit_position_re, value)
-  if match:
-    return int(match.group('position'))
-  raise RuntimeError('Could not get chromium commit position from test arg.')
-
-
 # Compiled regular expression matching strings like *.so, *.so.1, *.so.2, ...
 SO_FILENAME_REGEXP = re.compile(r'\.so(\.\d+)?$')
 
@@ -440,11 +426,6 @@
       type=os.path.realpath,
       help='File to which simplified JSON results will be written.')
   parser.add_argument(
-      '--output-dir',
-      help='Optional directory for histogram output file.  This argument is '
-      'automatically supplied by the recipe infrastructure when this script '
-      'is invoked by a recipe call to api.chromium.runtest().')
-  parser.add_argument(
       '--size-plugin-json-path',
       help='Optional path for json size data for the Gerrit binary size plugin',
   )
@@ -454,12 +435,6 @@
                            'fyi_sizes.json'),
       help='path to package size limits json file.  The path is relative to '
       'the workspace src directory')
-  parser.add_argument(
-      '--test-revision-cp',
-      help='Set the chromium commit point NNNNNN from a build property value '
-      'like "refs/heads/master@{#NNNNNNN}".  Intended for use in recipes with '
-      'the build property got_revision_cp',
-  )
   parser.add_argument('--verbose',
                       '-v',
                       action='store_true',
@@ -477,10 +452,6 @@
     for var in vars(args):
       print('  {}: {}'.format(var, getattr(args, var) or ''))
 
-  # Optionally prefix the output_dir to the histogram_path.
-  if args.output_dir and args.histogram_path:
-    args.histogram_path = os.path.join(args.output_dir, args.histogram_path)
-
   if not os.path.isdir(args.build_out_dir):
     raise Exception('Could not find build output directory "%s".' %
                     args.build_out_dir)
diff --git a/build/fuchsia/common_args.py b/build/fuchsia/common_args.py
index f23e8eb..31e063c 100644
--- a/build/fuchsia/common_args.py
+++ b/build/fuchsia/common_args.py
@@ -128,31 +128,9 @@
       logging.DEBUG if args.verbose else logging.WARN)
 
 
-# TODO(crbug.com/1121763): remove the need for additional_args
-def GetDeploymentTargetForArgs(additional_args=None):
+def GetDeploymentTargetForArgs(args):
   """Constructs a deployment target object using command line arguments.
      If needed, an additional_args dict can be used to supplement the
      command line arguments."""
 
-  # Determine target type from command line arguments.
-  device_type_parser = argparse.ArgumentParser()
-  _AddTargetSpecificationArgs(device_type_parser)
-  module_args, _ = device_type_parser.parse_known_args()
-  target_class = _GetTargetClass(module_args)
-
-  # Process command line args needed to initialize target in separate arg
-  # parser.
-  target_arg_parser = argparse.ArgumentParser()
-  target_class.RegisterArgs(target_arg_parser)
-  known_args, _ = target_arg_parser.parse_known_args()
-  target_args = vars(known_args)
-
-  # target_cpu is needed to determine target type, and fuchsia_out_dir
-  # is needed for devices with Fuchsia built from source code.
-  target_args.update({'target_cpu': module_args.target_cpu})
-  target_args.update({'fuchsia_out_dir': module_args.fuchsia_out_dir})
-
-  if additional_args:
-    target_args.update(additional_args)
-
-  return target_class(**target_args)
+  return _GetTargetClass(args).CreateFromArgs(args)
diff --git a/build/fuchsia/device_target.py b/build/fuchsia/device_target.py
index 854c572..0c9f247 100644
--- a/build/fuchsia/device_target.py
+++ b/build/fuchsia/device_target.py
@@ -121,6 +121,13 @@
       self._ssh_config_path = boot_data.GetSSHConfigPath(out_dir)
 
   @staticmethod
+  def CreateFromArgs(args):
+    return DeviceTarget(args.out_dir, args.target_cpu, args.host,
+                        args.node_name, args.port, args.ssh_config,
+                        args.fuchsia_out_dir, args.os_check,
+                        args.system_log_file)
+
+  @staticmethod
   def RegisterArgs(arg_parser):
     target.Target.RegisterArgs(arg_parser)
     device_args = arg_parser.add_argument_group('device', 'Device Arguments')
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index cdb34b7..e1e0af2a 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3.20210317.1.1
+3.20210317.3.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cdb34b7..e1e0af2a 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3.20210317.1.1
+3.20210317.3.1
diff --git a/build/fuchsia/qemu_target.py b/build/fuchsia/qemu_target.py
index 47cb7a3..057ea77 100644
--- a/build/fuchsia/qemu_target.py
+++ b/build/fuchsia/qemu_target.py
@@ -54,6 +54,12 @@
     self._require_kvm=require_kvm
     self._ram_size_mb=ram_size_mb
 
+  @staticmethod
+  def CreateFromArgs(args):
+    return QemuTarget(args.out_dir, args.target_cpu, args.system_log_file,
+                      args.cpu_cores, args.require_kvm, args.ram_size_mb,
+                      args.fuchsia_out_dir)
+
   def _IsKvmEnabled(self):
     kvm_supported = sys.platform.startswith('linux') and \
                     os.access('/dev/kvm', os.R_OK | os.W_OK)
diff --git a/build/fuchsia/target.py b/build/fuchsia/target.py
index ed716f5..6b88967 100644
--- a/build/fuchsia/target.py
+++ b/build/fuchsia/target.py
@@ -69,6 +69,10 @@
     self._command_runner = None
 
   @staticmethod
+  def CreateFromArgs(args):
+    raise NotImplementedError()
+
+  @staticmethod
   def RegisterArgs(arg_parser):
     common_args = arg_parser.add_argument_group(
         'target', 'Arguments that apply to all targets.')
diff --git a/build/fuchsia/test_runner.py b/build/fuchsia/test_runner.py
index 0903f309..dac3fa2 100755
--- a/build/fuchsia/test_runner.py
+++ b/build/fuchsia/test_runner.py
@@ -174,7 +174,7 @@
     test_realms = [TEST_REALM_NAME]
 
   try:
-    with GetDeploymentTargetForArgs() as target, \
+    with GetDeploymentTargetForArgs(args) as target, \
          SystemLogReader() as system_logger, \
          RunnerLogManager(args.runner_logs_dir, BuildIdsPaths(args.package)):
       target.Start()
diff --git a/chrome/OWNERS b/chrome/OWNERS
index 6e845bd..fb83168 100644
--- a/chrome/OWNERS
+++ b/chrome/OWNERS
@@ -28,6 +28,8 @@
 # structural changes, please get a review from a reviewer in this file.
 per-file *.gni=*
 per-file BUILD.gn=file://build/OWNERS
+per-file MAJOR_BRANCH_DATE=chrome-official-brancher@chops-service-accounts.iam.gserviceaccount.com
+per-file VERSION=chrome-official-brancher@chops-service-accounts.iam.gserviceaccount.com
 per-file VERSION=amineer@chromium.org
 per-file VERSION=anantha@chromium.org
 per-file VERSION=govind@chromium.org
diff --git a/chrome/VERSION b/chrome/VERSION
index 48c418af..d81a1b9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=91
 MINOR=0
-BUILD=4450
+BUILD=4451
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5f0ee88..bba12ce 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1546,6 +1546,7 @@
         "javatests/src/org/chromium/chrome/browser/vr/WebXrArLightEstimationTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/WebXrArTestFramework.java",
+        "javatests/src/org/chromium/chrome/browser/vr/WebXrArViewportScaleTest.java",
         "javatests/src/org/chromium/chrome/browser/vr/rules/ArPlaybackFile.java",
         "javatests/src/org/chromium/chrome/browser/vr/rules/ArTestRule.java",
         "javatests/src/org/chromium/chrome/browser/vr/rules/ChromeTabbedActivityArTestRule.java",
@@ -3507,6 +3508,7 @@
     "java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java",
     "java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java",
     "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java",
+    "java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java",
     "java/src/org/chromium/chrome/browser/signin/SigninBridge.java",
     "java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java",
     "java/src/org/chromium/chrome/browser/site_settings/CookieControlsServiceBridge.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 6da5cada..9164e20 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1196,6 +1196,7 @@
   "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java",
   "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMetrics.java",
   "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java",
+  "java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java",
   "java/src/org/chromium/chrome/browser/signin/SigninActivity.java",
   "java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java",
   "java/src/org/chromium/chrome/browser/signin/SigninBridge.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index 12501b99..46549c8 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -1038,6 +1038,10 @@
         android:exported="false"
         android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver">
     </receiver>  # DIFF-ANCHOR: 729144c9
+    <receiver  # DIFF-ANCHOR: e61d98d4
+        android:exported="false"
+        android:name="org.chromium.chrome.browser.sharing.sms_fetcher.SmsFetcherMessageHandler$NotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: e61d98d4
     <receiver  # DIFF-ANCHOR: aa6748fc
         android:exported="false"
         android:name="org.chromium.chrome.browser.upgrade.PackageReplacedBroadcastReceiver">
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index 09e7c58..d2da745 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -976,6 +976,10 @@
         android:exported="false"
         android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver">
     </receiver>  # DIFF-ANCHOR: 729144c9
+    <receiver  # DIFF-ANCHOR: e61d98d4
+        android:exported="false"
+        android:name="org.chromium.chrome.browser.sharing.sms_fetcher.SmsFetcherMessageHandler$NotificationReceiver">
+    </receiver>  # DIFF-ANCHOR: e61d98d4
     <receiver  # DIFF-ANCHOR: aa6748fc
         android:exported="false"
         android:name="org.chromium.chrome.browser.upgrade.PackageReplacedBroadcastReceiver">
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 19323693b..70de9b7 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1075,6 +1075,8 @@
             android:exported="false"/>
         <receiver android:name="org.chromium.chrome.browser.sharing.shared_clipboard.SharedClipboardMessageHandler$TryAgainReceiver"
             android:exported="false"/>
+        <receiver android:name="org.chromium.chrome.browser.sharing.sms_fetcher.SmsFetcherMessageHandler$NotificationReceiver"
+            android:exported="false"/>
 
         <receiver android:name="org.chromium.chrome.browser.offlinepages.prefetch.PrefetchedPagesNotifier$ClickReceiver"
             android:exported="false"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
index cb56a393..18aab73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/NavigationHandler.java
@@ -198,7 +198,7 @@
     boolean triggerUi(boolean forward, float x, float y) {
         // Triggering requests may come after the tab is nulled out
         // when the activity is being destroyed. Ignore it.
-        if (mTab == null) return false;
+        if (mTab == null || mTab.isDestroyed()) return false;
         mModel.set(DIRECTION, forward);
         boolean navigable = canNavigate(forward);
         if (navigable) {
@@ -226,7 +226,7 @@
      * @param forward {@code true} for forward navigation, or {@code false} for back.
      */
     void navigate(boolean forward) {
-        if (mTab == null) return;
+        if (mTab == null || mTab.isDestroyed()) return;
         if (forward) {
             mTab.goForward();
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
index 9ae6c3ec..1b6579bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
@@ -129,6 +129,11 @@
     public static final int NOTIFICATION_ID_TWA_DISCLOSURE_SUBSEQUENT = 14;
 
     /**
+     * Unique identifier for Sms Fetcher incoming notifications.
+     */
+    public static final int NOTIFICATION_ID_SMS_FETCHER_INCOMING = 15;
+
+    /**
      * Separator used to separate the notification origin from additional data such as the
      * developer specified tag. This and the prefix following it need to be the same as the one
      * specified in notification_id_generator.cc.
@@ -153,6 +158,7 @@
     public static final String GROUP_CLICK_TO_CALL = "ClickToCall";
     public static final String GROUP_SHARED_CLIPBOARD = "SharedClipboard";
     public static final String GROUP_SHARE_SAVE_IMAGE = "ShareSaveImage";
+    public static final String GROUP_SMS_FETCHER = "SmsFetcher";
 
     // Web notification group names are set dynamically as this prefix + notification origin.
     // For example, 'Web:chromium.org' for a notification from chromium.org.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
index b21a2bd..cda78cb0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationUmaTracker.java
@@ -52,7 +52,7 @@
             SystemNotificationType.TRUSTED_WEB_ACTIVITY_SITES, SystemNotificationType.OFFLINE_PAGES,
             SystemNotificationType.SEND_TAB_TO_SELF, SystemNotificationType.UPDATES,
             SystemNotificationType.CLICK_TO_CALL, SystemNotificationType.SHARED_CLIPBOARD,
-            SystemNotificationType.PERMISSION_REQUESTS,
+            SystemNotificationType.SMS_FETCHER, SystemNotificationType.PERMISSION_REQUESTS,
             SystemNotificationType.PERMISSION_REQUESTS_HIGH, SystemNotificationType.ANNOUNCEMENT,
             SystemNotificationType.SHARE_SAVE_IMAGE, SystemNotificationType.TWA_DISCLOSURE_INITIAL,
             SystemNotificationType.TWA_DISCLOSURE_SUBSEQUENT,
@@ -91,8 +91,9 @@
         int CHROME_REENGAGEMENT_2 = 26;
         int CHROME_REENGAGEMENT_3 = 27;
         int PRICE_DROP_ALERTS = 28;
+        int SMS_FETCHER = 29;
 
-        int NUM_ENTRIES = 29;
+        int NUM_ENTRIES = 30;
     }
 
     /*
@@ -211,6 +212,10 @@
                 recordNotificationAgeHistogram(
                         "Mobile.SystemNotification.Content.Click.Age.SharedClipboard", createTime);
                 break;
+            case SystemNotificationType.SMS_FETCHER:
+                recordNotificationAgeHistogram(
+                        "Mobile.SystemNotification.Content.Click.Age.SmsFetcher", createTime);
+                break;
         }
     }
 
@@ -241,6 +246,10 @@
                 recordNotificationAgeHistogram(
                         "Mobile.SystemNotification.Dismiss.Age.SharedClipboard", createTime);
                 break;
+            case SystemNotificationType.SMS_FETCHER:
+                recordNotificationAgeHistogram(
+                        "Mobile.SystemNotification.Dismiss.Age.SmsFetcher", createTime);
+                break;
         }
     }
 
@@ -273,6 +282,10 @@
                 recordNotificationAgeHistogram(
                         "Mobile.SystemNotification.Action.Click.Age.SharedClipboard", createTime);
                 break;
+            case SystemNotificationType.SMS_FETCHER:
+                recordNotificationAgeHistogram(
+                        "Mobile.SystemNotification.Action.Click.Age.SmsFetcher", createTime);
+                break;
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
index d324f5a..c821850 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/SharingNotificationUtil.java
@@ -39,6 +39,7 @@
      * @param group The notification group.
      * @param id The notification id.
      * @param contentIntent The notification content intent.
+     * @param deleteIntent The notification delete intent.
      * @param contentTitle The notification title text.
      * @param contentText The notification content text.
      * @param largeIconId The large notification icon resource id, 0 if not used.
@@ -46,9 +47,9 @@
      * @param startsActivity Whether the {@code contentIntent} starts an Activity.
      */
     public static void showNotification(@SystemNotificationType int type, String group, int id,
-            PendingIntentProvider contentIntent, String contentTitle, String contentText,
-            @DrawableRes int smallIconId, @DrawableRes int largeIconId, int color,
-            boolean startsActivity) {
+            PendingIntentProvider contentIntent, PendingIntentProvider deleteIntent,
+            String contentTitle, String contentText, @DrawableRes int smallIconId,
+            @DrawableRes int largeIconId, int color, boolean startsActivity) {
         Context context = ContextUtils.getApplicationContext();
         Resources resources = context.getResources();
         NotificationWrapperBuilder builder =
@@ -74,6 +75,10 @@
             builder.setContentIntent(contentIntent);
         }
 
+        if (deleteIntent != null) {
+            builder.setDeleteIntent(deleteIntent);
+        }
+
         if (largeIconId != 0) {
             Bitmap largeIcon = BitmapFactory.decodeResource(resources, largeIconId);
             if (largeIcon != null) builder.setLargeIcon(largeIcon);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
index 7b9bfb1..5bec93bd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -59,6 +59,7 @@
                 NotificationUmaTracker.SystemNotificationType.CLICK_TO_CALL,
                 NotificationConstants.GROUP_CLICK_TO_CALL,
                 NotificationConstants.NOTIFICATION_ID_CLICK_TO_CALL_ERROR, /*contentIntent=*/null,
+                /*deleteIntent=*/null,
                 context.getResources().getString(
                         R.string.click_to_call_dialer_absent_notification_title),
                 context.getResources().getString(
@@ -106,7 +107,7 @@
                 NotificationUmaTracker.SystemNotificationType.CLICK_TO_CALL,
                 NotificationConstants.GROUP_CLICK_TO_CALL,
                 NotificationConstants.NOTIFICATION_ID_CLICK_TO_CALL,
-                getContentIntentProvider(phoneNumber), phoneNumber,
+                getContentIntentProvider(phoneNumber), /*deleteIntent=*/null, phoneNumber,
                 context.getResources().getString(R.string.click_to_call_notification_text),
                 R.drawable.ic_devices_16dp, R.drawable.ic_dialer_icon_blue_40dp,
                 R.color.default_icon_color_blue, /*startsActivity=*/true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
index 5f3a4ca..a0d820a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java
@@ -212,7 +212,8 @@
                 NotificationUmaTracker.SystemNotificationType.SHARED_CLIPBOARD,
                 NotificationConstants.GROUP_SHARED_CLIPBOARD,
                 NotificationConstants.NOTIFICATION_ID_SHARED_CLIPBOARD_INCOMING, contentIntent,
-                notificationTitle, resources.getString(R.string.shared_clipboard_notification_text),
+                /*deleteIntent=*/null, notificationTitle,
+                resources.getString(R.string.shared_clipboard_notification_text),
                 R.drawable.ic_devices_16dp, R.drawable.shared_clipboard_40dp,
                 R.color.default_icon_color_blue, /*startsActivity=*/false);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java
new file mode 100644
index 0000000..99745d7
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/sms_fetcher/SmsFetcherMessageHandler.java
@@ -0,0 +1,115 @@
+// 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.
+
+package org.chromium.chrome.browser.sharing.sms_fetcher;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.notifications.NotificationConstants;
+import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
+import org.chromium.chrome.browser.sharing.SharingNotificationUtil;
+import org.chromium.components.browser_ui.notifications.PendingIntentProvider;
+
+/**
+ * Handles Sms Fetcher messages and notifications for Android.
+ */
+public class SmsFetcherMessageHandler {
+    private static final String NOTIFICATION_ACTION_TAP = "sms_fetcher_notification.tap";
+    private static final String NOTIFICATION_ACTION_DISMISS = "sms_fetcher_notification.dismiss";
+    private static final String TAG = "SmsMessageHandler";
+    private static final boolean DEBUG = false;
+    private static long sSmsFetcherMessageHandlerAndroid;
+    private static String sOrigin;
+
+    /**
+     * Handles the interaction of an incoming notification when an expected SMS arrives.
+     */
+    public static final class NotificationReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            boolean nativeIsDestroyed = sSmsFetcherMessageHandlerAndroid == 0;
+            RecordHistogram.recordBooleanHistogram(
+                    "Sharing.SmsFetcherTapWithChromeDestroyed", nativeIsDestroyed);
+            // This could happen if the user manually swipes away Chrome from the task switcher or
+            // the OS decides to destroy Chrome due to lack of memory etc. In these cases we just
+            // close the notification.
+            if (nativeIsDestroyed) return;
+            switch (action) {
+                case NOTIFICATION_ACTION_TAP:
+                    if (DEBUG) Log.d(TAG, "Notification tapped");
+                    SmsFetcherMessageHandlerJni.get().onConfirm(
+                            sSmsFetcherMessageHandlerAndroid, sOrigin);
+                    break;
+                case NOTIFICATION_ACTION_DISMISS:
+                    if (DEBUG) Log.d(TAG, "Notification dismissed");
+                    SmsFetcherMessageHandlerJni.get().onDismiss(
+                            sSmsFetcherMessageHandlerAndroid, sOrigin);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Ask the user to tap the notification to verify the sms verification code.
+     *
+     * @param oneTimeCode The one time code from SMS
+     * @param origin The origin from the SMS
+     * @param smsFetcherMessageHandlerAndroid The native handler
+     */
+    @CalledByNative
+    private static void showNotification(
+            String oneTimeCode, String origin, long smsFetcherMessageHandlerAndroid) {
+        sOrigin = origin;
+        sSmsFetcherMessageHandlerAndroid = smsFetcherMessageHandlerAndroid;
+        Context context = ContextUtils.getApplicationContext();
+        PendingIntentProvider contentIntent = PendingIntentProvider.getBroadcast(context,
+                /*requestCode=*/0,
+                new Intent(context, NotificationReceiver.class).setAction(NOTIFICATION_ACTION_TAP),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        PendingIntentProvider deleteIntent = PendingIntentProvider.getBroadcast(context,
+                /*requestCode=*/0,
+                new Intent(context, NotificationReceiver.class)
+                        .setAction(NOTIFICATION_ACTION_DISMISS),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        Resources resources = context.getResources();
+        String notificationText =
+                resources.getString(R.string.sms_fetcher_notification_text, oneTimeCode, origin);
+        SharingNotificationUtil.showNotification(
+                NotificationUmaTracker.SystemNotificationType.SMS_FETCHER,
+                NotificationConstants.GROUP_SMS_FETCHER,
+                NotificationConstants.NOTIFICATION_ID_SMS_FETCHER_INCOMING, contentIntent,
+                deleteIntent, resources.getString(R.string.sms_fetcher_notification_title),
+                notificationText, R.drawable.ic_devices_48dp, R.drawable.infobar_chrome,
+                R.color.infobar_icon_drawable_color, /*startsActivity=*/false);
+    }
+
+    @CalledByNative
+    private static void dismissNotification() {
+        SharingNotificationUtil.dismissNotification(NotificationConstants.GROUP_SMS_FETCHER,
+                NotificationConstants.NOTIFICATION_ID_SMS_FETCHER_INCOMING);
+    }
+
+    @CalledByNative
+    private static void reset() {
+        sSmsFetcherMessageHandlerAndroid = 0;
+        sOrigin = "";
+    }
+
+    @NativeMethods
+    interface Natives {
+        void onConfirm(long nativeSmsFetchRequestHandler, String origin);
+        void onDismiss(long nativeSmsFetchRequestHandler, String origin);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
index f488483e..36f6453 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/site_settings/ChromeSiteSettingsDelegate.java
@@ -35,7 +35,6 @@
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
 import org.chromium.components.embedder_support.util.Origin;
-import org.chromium.components.page_info.PageInfoFeatureList;
 import org.chromium.content_public.browser.ContentFeatureList;
 import org.chromium.content_public.common.ContentSwitches;
 
@@ -202,11 +201,6 @@
     }
 
     @Override
-    public boolean isPageInfoV2Enabled() {
-        return PageInfoFeatureList.isEnabled(PageInfoFeatureList.PAGE_INFO_V2);
-    }
-
-    @Override
     public boolean isHelpAndFeedbackEnabled() {
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 2f34b84..eaa80ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -20,7 +20,6 @@
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.layouts.LayoutStateProvider;
-import org.chromium.chrome.browser.layouts.LayoutType;
 import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.NewTabPageDelegate;
@@ -103,6 +102,7 @@
     private boolean mIsIncognito;
     private boolean mIsUsingBrandColor;
     private boolean mShouldShowOmniboxInOverviewMode;
+    private boolean mIsShowingTabSwitcher;
 
     private long mNativeLocationBarModelAndroid;
     private ObserverList<LocationBarDataProvider.Observer> mLocationBarDataObservers =
@@ -361,8 +361,7 @@
     public boolean isInOverviewAndShowingOmnibox() {
         if (!mShouldShowOmniboxInOverviewMode) return false;
 
-        return mLayoutStateProvider != null
-                && mLayoutStateProvider.isLayoutVisible(LayoutType.TAB_SWITCHER);
+        return mLayoutStateProvider != null && mIsShowingTabSwitcher;
     }
 
     /**
@@ -575,6 +574,18 @@
                 mNativeLocationBarModelAndroid, LocationBarModel.this);
     }
 
+    /**
+     * Set whether tab switcher is showing or not and notify changes.
+     * @param isShowingTabSwitcher Whether tab switcher is showing or not.
+     */
+    public void setIsShowingTabSwitcher(boolean isShowingTabSwitcher) {
+        mIsShowingTabSwitcher = isShowingTabSwitcher;
+        notifyTitleChanged();
+        notifyUrlChanged();
+        notifyPrimaryColorChanged();
+        notifySecurityStateChanged();
+    }
+
     @NativeMethods
     interface Natives {
         long init(LocationBarModel caller);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index b69b69d..5b7a36cb2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -767,6 +767,7 @@
             @Override
             public void onStartedShowing(@LayoutType int layoutType, boolean showToolbar) {
                 if (layoutType == LayoutType.TAB_SWITCHER) {
+                    mLocationBarModel.setIsShowingTabSwitcher(true);
                     mToolbar.setTabSwitcherMode(true, showToolbar, false);
                     updateButtonStatus();
                     if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) {
@@ -780,6 +781,7 @@
             public void onStartedHiding(
                     @LayoutType int layoutType, boolean showToolbar, boolean delayAnimation) {
                 if (layoutType == LayoutType.TAB_SWITCHER) {
+                    mLocationBarModel.setIsShowingTabSwitcher(false);
                     mToolbar.setTabSwitcherMode(false, showToolbar, delayAnimation);
                     updateButtonStatus();
                 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
index 822e62e..fa88280c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -1879,8 +1879,6 @@
             mPendingTriggerUrlFocusRequest = true;
         }
 
-        if (inTabSwitcherMode) mUrlBar.setText("");
-
         return true;
     }
 
@@ -1915,14 +1913,6 @@
         } else {
             updateViewsForTabSwitcherMode();
         }
-
-        // Set the url bar text back after finished hiding the tab switcher.
-        if (getToolbarDataProvider().shouldShowLocationBarInOverviewMode()
-                && mTabSwitcherState == STATIC_TAB && getToolbarDataProvider() != null
-                && getToolbarDataProvider().getUrlBarData() != null) {
-            assert !getToolbarDataProvider().isInOverviewAndShowingOmnibox();
-            mUrlBar.setText(getToolbarDataProvider().getUrlBarData().displayText);
-        }
     }
 
     @Override
@@ -2191,11 +2181,6 @@
         if (mTabSwitcherAnimationTabStackDrawable != null) {
             mTabSwitcherAnimationTabStackDrawable.updateForTabCount(numberOfTabs, isIncognito);
         }
-
-        if (getToolbarDataProvider().isInOverviewAndShowingOmnibox()
-                && getToolbarDataProvider().shouldShowLocationBarInOverviewMode()) {
-            mUrlBar.setText("");
-        }
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateAssistContentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateAssistContentTest.java
index 0df40f5..e07860b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateAssistContentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateAssistContentTest.java
@@ -18,6 +18,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -150,6 +151,7 @@
     @MediumTest
     @Restriction(Restriction.RESTRICTION_TYPE_INTERNET)
     @Features.EnableFeatures({ChromeFeatureList.TRANSLATE_ASSIST_CONTENT})
+    @DisabledTest(message = "https://crbug.com/1189385")
     public void testAssistContentNonTranslatePage()
             throws TimeoutException, ExecutionException, JSONException {
         if (shouldSkipDueToNetworkService()) return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArViewportScaleTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArViewportScaleTest.java
new file mode 100644
index 0000000..53e9981
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArViewportScaleTest.java
@@ -0,0 +1,103 @@
+// 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.
+
+package org.chromium.chrome.browser.vr;
+
+import static org.chromium.chrome.browser.vr.WebXrArTestFramework.PAGE_LOAD_TIMEOUT_S;
+
+import android.os.Build;
+
+import androidx.test.filters.MediumTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
+import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
+import org.chromium.base.test.params.ParameterSet;
+import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
+import org.chromium.chrome.browser.vr.util.ArTestRuleUtils;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * End-to-end tests for testing WebXR for dynamic viewport scale behavior in AR mode.
+ */
+@RunWith(ParameterizedRunner.class)
+@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        "enable-features=WebXR,WebXRARModule,WebXRHitTest,LogJsConsoleMessages"})
+@MinAndroidSdkLevel(Build.VERSION_CODES.N) // WebXR for AR is only supported on N+
+public class WebXrArViewportScaleTest {
+    @ClassParameter
+    private static List<ParameterSet> sClassParams =
+            ArTestRuleUtils.generateDefaultTestRuleParameters();
+    @Rule
+    public RuleChain mRuleChain;
+
+    private ChromeActivityTestRule mTestRule;
+    private WebXrArTestFramework mWebXrArTestFramework;
+
+    public WebXrArViewportScaleTest(Callable<ChromeActivityTestRule> callable) throws Exception {
+        mTestRule = callable.call();
+        mRuleChain = ArTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule);
+    }
+
+    @Before
+    public void setUp() {
+        mWebXrArTestFramework = new WebXrArTestFramework(mTestRule);
+    }
+
+    /**
+     * Tests that viewport scaling works when requested at the start of a frame.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testViewportScaleSameFrame() {
+        mWebXrArTestFramework.loadFileAndAwaitInitialization(
+                "webxr_test_basic_viewport_scale", PAGE_LOAD_TIMEOUT_S);
+        mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrArTestFramework.executeStepAndWait("stepRequestViewportScaleSameFrame()");
+        mWebXrArTestFramework.endTest();
+    }
+
+    /**
+     * Tests that viewport scaling applies to the next frame if requested after gl.viewport.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testViewportScaleNextFrame() {
+        mWebXrArTestFramework.loadFileAndAwaitInitialization(
+                "webxr_test_basic_viewport_scale", PAGE_LOAD_TIMEOUT_S);
+        mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrArTestFramework.executeStepAndWait("stepRequestViewportScaleNextFrame()");
+        mWebXrArTestFramework.endTest();
+    }
+
+    /**
+     * Tests that dynamic viewport scaling using the recommended viewport scale works.
+     */
+    @Test
+    @MediumTest
+    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
+    public void testRecommendedViewportScale() {
+        mWebXrArTestFramework.loadFileAndAwaitInitialization(
+                "webxr_test_basic_viewport_scale", PAGE_LOAD_TIMEOUT_S);
+        mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
+        mWebXrArTestFramework.executeStepAndWait("stepRequestRecommendedViewportScale()");
+        mWebXrArTestFramework.endTest();
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
index 43319c3d..77757137 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/LocationBarModelUnitTest.java
@@ -209,4 +209,23 @@
         regularLocationBarModel.notifyNtpStartedLoading();
         verify(mLocationBarDataObserver).onNtpStartedLoading();
     }
+
+    @Test
+    @MediumTest
+    public void testObserversNotified_setIsShowingTabSwitcher() {
+        LocationBarModel regularLocationBarModel =
+                new TestRegularLocationBarModel(null, mSearchEngineLogoUtils);
+        regularLocationBarModel.addObserver(mLocationBarDataObserver);
+
+        verify(mLocationBarDataObserver, never()).onTitleChanged();
+        verify(mLocationBarDataObserver, never()).onUrlChanged();
+        verify(mLocationBarDataObserver, never()).onPrimaryColorChanged();
+        verify(mLocationBarDataObserver, never()).onSecurityStateChanged();
+
+        regularLocationBarModel.setIsShowingTabSwitcher(true);
+        verify(mLocationBarDataObserver).onTitleChanged();
+        verify(mLocationBarDataObserver).onUrlChanged();
+        verify(mLocationBarDataObserver).onPrimaryColorChanged();
+        verify(mLocationBarDataObserver).onSecurityStateChanged();
+    }
 }
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 10d0ca4..e54ee25e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -33,7 +33,7 @@
     Time limit removed for <ph name="APP_NAME">$1<ex>Gmail</ex></ph>
   </message>
 
-  <!-- Wallpaper Manager -->
+  <!-- Wallpaper Manager (Deprecated Chrome App Version) -->
   <message name="IDS_WALLPAPER_MANAGER_APP_NAME" desc="Name of the app which allows users to pick their wallpaper.">
     Wallpaper Picker
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 9db2d22..340e3f5 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1590,8 +1590,6 @@
     "sharing/sharing_sync_preference.h",
     "sharing/sharing_utils.cc",
     "sharing/sharing_utils.h",
-    "sharing/sms/sms_fetch_request_handler.cc",
-    "sharing/sms/sms_fetch_request_handler.h",
     "sharing/sms/sms_flags.cc",
     "sharing/sms/sms_flags.h",
     "sharing/sms/sms_remote_fetcher.cc",
@@ -3152,6 +3150,8 @@
       "sharing/shared_clipboard/shared_clipboard_message_handler_android.h",
       "sharing/sharing_service_proxy_android.cc",
       "sharing/sharing_service_proxy_android.h",
+      "sharing/sms/sms_fetch_request_handler.cc",
+      "sharing/sms/sms_fetch_request_handler.h",
       "shell_integration_android.cc",
       "signin/identity_services_provider_android.cc",
       "signin/signin_manager_android_factory.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index bf106f3..65b4ffae 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3093,12 +3093,6 @@
      flag_descriptions::kShowBluetoothDebugLogToggleName,
      flag_descriptions::kShowBluetoothDebugLogToggleDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kShowBluetoothDebugLogToggle)},
-    {"enable-bluetooth-verbose-logs-for-googlers",
-     flag_descriptions::kEnableBluetoothVerboseLogsForGooglersName,
-     flag_descriptions::kEnableBluetoothVerboseLogsForGooglersDescription,
-     kOsCrOS,
-     FEATURE_VALUE_TYPE(
-         chromeos::features::kEnableBluetoothVerboseLogsForGooglers)},
     {"show-taps", flag_descriptions::kShowTapsName,
      flag_descriptions::kShowTapsDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(ash::switches::kShowTaps)},
@@ -4188,9 +4182,6 @@
     {"files-app-copy-image", flag_descriptions::kFilesAppCopyImageName,
      flag_descriptions::kFilesAppCopyImageDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kEnableFilesAppCopyImage)},
-    {"files-camera-folder", flag_descriptions::kFilesCameraFolderName,
-     flag_descriptions::kFilesCameraFolderDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kFilesCameraFolder)},
     {"files-filters-in-recents", flag_descriptions::kFiltersInRecentsName,
      flag_descriptions::kFiltersInRecentsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kFiltersInRecents)},
@@ -5989,12 +5980,6 @@
      flag_descriptions::kSafetyTipDescription, kOsAll,
      FEATURE_VALUE_TYPE(security_state::features::kSafetyTipUI)},
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    {"crostini-webui-upgrader", flag_descriptions::kCrostiniWebUIUpgraderName,
-     flag_descriptions::kCrostiniWebUIUpgraderDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kCrostiniWebUIUpgrader)},
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
     {"turn-off-streaming-media-caching-on-battery",
      flag_descriptions::kTurnOffStreamingMediaCachingOnBatteryName,
      flag_descriptions::kTurnOffStreamingMediaCachingOnBatteryDescription,
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc
index bb82573..4f520d9 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.cc
+++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -12,6 +12,7 @@
 #include "base/bind.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
@@ -46,8 +47,8 @@
 #include "ash/public/cpp/window_tree_host_lookup.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/browser/ash/accessibility/magnification_manager.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes_util.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/ui_base_features.h"
@@ -657,4 +658,33 @@
   return RespondNow(NoArguments());
 }
 
-#endif  // defined (OS_CHROMEOS)
+ExtensionFunction::ResponseAction
+AccessibilityPrivateShowConfirmationDialogFunction::Run() {
+  std::unique_ptr<accessibility_private::ShowConfirmationDialog::Params>
+      params =
+          accessibility_private::ShowConfirmationDialog::Params::Create(*args_);
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  std::u16string title = base::UTF8ToUTF16(params->title);
+  std::u16string description = base::UTF8ToUTF16(params->description);
+  ash::AccessibilityController::Get()->ShowConfirmationDialog(
+      title, description,
+      base::BindOnce(
+          &AccessibilityPrivateShowConfirmationDialogFunction::OnDialogResult,
+          base::RetainedRef(this), /* confirmed */ true),
+      base::BindOnce(
+          &AccessibilityPrivateShowConfirmationDialogFunction::OnDialogResult,
+          base::RetainedRef(this), /* not confirmed */ false),
+      base::BindOnce(
+          &AccessibilityPrivateShowConfirmationDialogFunction::OnDialogResult,
+          base::RetainedRef(this), /* not confirmed */ false));
+
+  return RespondLater();
+}
+
+void AccessibilityPrivateShowConfirmationDialogFunction::OnDialogResult(
+    bool confirmed) {
+  Respond(OneArgument(base::Value(confirmed)));
+}
+
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h
index 448e3a9..1f56af9 100644
--- a/chrome/browser/accessibility/accessibility_extension_api.h
+++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -215,6 +215,17 @@
   DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.updateSelectToSpeakPanel",
                              ACCESSIBILITY_PRIVATE_UPDATESELECTTOSPEAKPANEL)
 };
+
+// API function that shows a confirmation dialog, with callbacks for
+// confirm/cancel.
+class AccessibilityPrivateShowConfirmationDialogFunction
+    : public ExtensionFunction {
+  ~AccessibilityPrivateShowConfirmationDialogFunction() override = default;
+  ResponseAction Run() override;
+  void OnDialogResult(bool confirmed);
+  DECLARE_EXTENSION_FUNCTION("accessibilityPrivate.showConfirmationDialog",
+                             ACCESSIBILITY_PRIVATE_SHOWCONFIRMATIONDIALOG)
+};
 #endif  // defined (OS_CHROMEOS)
 
 #endif  // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_
diff --git a/chrome/browser/accessibility/accessibility_ui.cc b/chrome/browser/accessibility/accessibility_ui.cc
index eed11ee2..dff59cf 100644
--- a/chrome/browser/accessibility/accessibility_ui.cc
+++ b/chrome/browser/accessibility/accessibility_ui.cc
@@ -132,6 +132,8 @@
 
 std::unique_ptr<base::DictionaryValue> BuildTargetDescriptor(
     content::RenderViewHost* rvh) {
+  TRACE_EVENT1("accessibility", "BuildTargetDescriptor", "render_view_host",
+               rvh);
   content::WebContents* web_contents =
       content::WebContents::FromRenderViewHost(rvh);
   ui::AXMode accessibility_mode;
diff --git a/chrome/browser/apps/app_service/arc_apps.h b/chrome/browser/apps/app_service/arc_apps.h
index 011d3ef..6665e02 100644
--- a/chrome/browser/apps/app_service/arc_apps.h
+++ b/chrome/browser/apps/app_service/arc_apps.h
@@ -23,8 +23,8 @@
 #include "chrome/browser/apps/app_service/arc_icon_once_loader.h"
 #include "chrome/browser/apps/app_service/icon_key_util.h"
 #include "chrome/browser/apps/app_service/paused_apps.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/intent_helper/arc_intent_helper_observer.h"
diff --git a/chrome/browser/apps/app_service/menu_util.h b/chrome/browser/apps/app_service/menu_util.h
index 1793e4d..7dfd589 100644
--- a/chrome/browser/apps/app_service/menu_util.h
+++ b/chrome/browser/apps/app_service/menu_util.h
@@ -10,7 +10,7 @@
 
 #include "base/callback.h"
 #include "base/strings/string_piece.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "ui/base/models/menu_separator_types.h"
 #include "ui/base/models/simple_menu_model.h"
@@ -93,6 +93,9 @@
 // id.
 apps::mojom::MenuType MenuTypeFromString(base::StringPiece menu_type);
 
+// A size of square shortcut menu item icons in the context menu.
+constexpr int kAppShortcutIconSizeDip = 32;
+
 }  // namespace apps
 
 #endif  // CHROME_BROWSER_APPS_APP_SERVICE_MENU_UTIL_H_
diff --git a/chrome/browser/apps/app_service/web_apps_chromeos.cc b/chrome/browser/apps/app_service/web_apps_chromeos.cc
index 170845b..41043b7 100644
--- a/chrome/browser/apps/app_service/web_apps_chromeos.cc
+++ b/chrome/browser/apps/app_service/web_apps_chromeos.cc
@@ -317,10 +317,6 @@
 
     gfx::ImageSkia icon;
     if (menu_item_icon_bitmaps) {
-      // TODO(crbug.com/1140356): Unify this constant with kAppShortcutIconSize
-      // from ArcAppShortcutsRequest class.
-      constexpr int kAppShortcutIconSizeDip = 32;
-
       // TODO(crbug.com/1152661): Remove kCrOsStandardIcon and add
       // kCrOsStandardBackground|kCrOsStandardMask effects for web app menu
       // maskable icons.
@@ -445,15 +441,25 @@
         continue;
       }
       apps::mojom::AppPtr app = apps::mojom::App::New();
-      app->app_type = apps::mojom::AppType::kWeb;
+      app->app_type = app_type();
       app->app_id = web_app->app_id();
       UpdateAppDisabledMode(app);
       apps.push_back(std::move(app));
     }
   }
+
+  const bool should_notify_initialized = false;
+  if (subscribers().size() == 1) {
+    auto& subscriber = *subscribers().begin();
+    subscriber->OnApps(std::move(apps), app_type(), should_notify_initialized);
+    return;
+  }
   for (auto& subscriber : subscribers()) {
-    subscriber->OnApps(std::move(apps), apps::mojom::AppType::kWeb,
-                       false /* should_notify_initialized */);
+    std::vector<apps::mojom::AppPtr> cloned_apps;
+    for (const auto& app : apps)
+      cloned_apps.push_back(app.Clone());
+    subscriber->OnApps(std::move(cloned_apps), app_type(),
+                       should_notify_initialized);
   }
 }
 
diff --git a/chrome/browser/apps/intent_helper/OWNERS b/chrome/browser/apps/intent_helper/OWNERS
index 1e68db6..d339cb2 100644
--- a/chrome/browser/apps/intent_helper/OWNERS
+++ b/chrome/browser/apps/intent_helper/OWNERS
@@ -3,4 +3,4 @@
 # For ARC related code
 djacobo@chromium.org
 # For ARC related code, backup reviewers
-file://chrome/browser/chromeos/arc/OWNERS
+file://chrome/browser/ash/arc/OWNERS
diff --git a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc b/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
similarity index 63%
rename from chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
rename to chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
index e2b6aadd..3534f59 100644
--- a/chrome/browser/accessibility/accessibility_extension_api_browsertest.cc
+++ b/chrome/browser/ash/accessibility/accessibility_extension_api_browsertest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/accessibility/accessibility_confirmation_dialog.h"
+#include "ash/accessibility/accessibility_controller_impl.h"
+#include "ash/shell.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -12,6 +15,7 @@
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/test/browser_test.h"
+#include "extensions/test/result_catcher.h"
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/base/ui_base_features.h"
 
@@ -104,6 +108,69 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest, AcceptConfirmationDialog) {
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "accept_confirmation_dialog.html"))
+      << message_;
+
+  // The test has requested to open the confirmation dialog. Check that
+  // it was created, then confirm it.
+  ash::AccessibilityConfirmationDialog* dialog_ =
+      ash::Shell::Get()
+          ->accessibility_controller()
+          ->GetConfirmationDialogForTest();
+  ASSERT_NE(dialog_, nullptr);
+
+  EXPECT_EQ(dialog_->GetWindowTitle(), u"Confirm me! 🐶");
+
+  // Accept the dialog and wait for the JS test to get the confirmation.
+  ResultCatcher catcher;
+  dialog_->Accept();
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest, CancelConfirmationDialog) {
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "cancel_confirmation_dialog.html"))
+      << message_;
+
+  // The test has requested to open the confirmation dialog. Check that
+  // it was created, then cancel it.
+  ash::AccessibilityConfirmationDialog* dialog_ =
+      ash::Shell::Get()
+          ->accessibility_controller()
+          ->GetConfirmationDialogForTest();
+  ASSERT_NE(dialog_, nullptr);
+
+  EXPECT_EQ(dialog_->GetWindowTitle(), u"Cancel me!");
+
+  // Cancel the dialog and wait for the JS test to get the callback.
+  ResultCatcher catcher;
+  dialog_->Cancel();
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityPrivateApiTest, CloseConfirmationDialog) {
+  ASSERT_TRUE(RunExtensionSubtest("accessibility_private/",
+                                  "cancel_confirmation_dialog.html"))
+      << message_;
+
+  // The test has requested to open the confirmation dialog. Check that
+  // it was created, then close it.
+  ash::AccessibilityConfirmationDialog* dialog_ =
+      ash::Shell::Get()
+          ->accessibility_controller()
+          ->GetConfirmationDialogForTest();
+  ASSERT_TRUE(dialog_ != nullptr);
+
+  EXPECT_EQ(dialog_->GetWindowTitle(), u"Cancel me!");
+
+  // Close the dialog and wait for the JS test to get the callback.
+  ResultCatcher catcher;
+  dialog_->Close();
+  EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
+}
+
 class AccessibilityPrivateApiFeatureEnabledTest : public ExtensionApiTest {
  public:
   void SetUp() override {
diff --git a/chrome/browser/ash/account_manager/account_manager_migrator.cc b/chrome/browser/ash/account_manager/account_manager_migrator.cc
index 1e3288a8..b23e4d11 100644
--- a/chrome/browser/ash/account_manager/account_manager_migrator.cc
+++ b/chrome/browser/ash/account_manager/account_manager_migrator.cc
@@ -24,11 +24,11 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/account_manager_facade_factory.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager_observer.h"
 #include "chrome/browser/profiles/profile.h"
diff --git a/chrome/browser/ash/app_mode/kiosk_app_manager.cc b/chrome/browser/ash/app_mode/kiosk_app_manager.cc
index 84cce1b..73f7b65 100644
--- a/chrome/browser/ash/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/ash/app_mode/kiosk_app_manager.cc
@@ -31,8 +31,8 @@
 #include "chrome/browser/ash/app_mode/kiosk_external_updater.h"
 #include "chrome/browser/ash/app_mode/pref_names.h"
 #include "chrome/browser/ash/login/session/user_session_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
@@ -83,7 +83,7 @@
 // Check for presence of machine owner public key file.
 void CheckOwnerFilePresence(bool *present) {
   scoped_refptr<ownership::OwnerKeyUtil> util =
-      OwnerSettingsServiceChromeOSFactory::GetInstance()->GetOwnerKeyUtil();
+      OwnerSettingsServiceAshFactory::GetInstance()->GetOwnerKeyUtil();
   *present = util.get() && util->IsPublicKeyPresent();
 }
 
@@ -186,7 +186,7 @@
 }
 
 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id,
-                                       OwnerSettingsServiceChromeOS* service) {
+                                       OwnerSettingsServiceAsh* service) {
   SetAutoLoginState(AutoLoginState::kRequested);
   // Clean first, so the proper change callbacks are triggered even
   // if we are only changing AutoLoginState here.
@@ -449,7 +449,7 @@
 }
 
 void KioskAppManager::AddApp(const std::string& app_id,
-                             OwnerSettingsServiceChromeOS* service) {
+                             OwnerSettingsServiceAsh* service) {
   std::vector<policy::DeviceLocalAccount> device_local_accounts =
       policy::GetDeviceLocalAccounts(CrosSettings::Get());
 
@@ -474,7 +474,7 @@
 }
 
 void KioskAppManager::RemoveApp(const std::string& app_id,
-                                OwnerSettingsServiceChromeOS* service) {
+                                OwnerSettingsServiceAsh* service) {
   // Resets auto launch app if it is the removed app.
   if (auto_launch_app_id_ == app_id)
     SetAutoLaunchApp(std::string(), service);
diff --git a/chrome/browser/ash/app_mode/kiosk_app_manager.h b/chrome/browser/ash/app_mode/kiosk_app_manager.h
index 757d2863..48fedfa 100644
--- a/chrome/browser/ash/app_mode/kiosk_app_manager.h
+++ b/chrome/browser/ash/app_mode/kiosk_app_manager.h
@@ -44,7 +44,7 @@
 
 class KioskAppData;
 class KioskExternalUpdater;
-class OwnerSettingsServiceChromeOS;
+class OwnerSettingsServiceAsh;
 
 // KioskAppManager manages cached app data.
 class KioskAppManager : public KioskAppManagerBase,
@@ -127,7 +127,7 @@
 
   // Sets |app_id| as the app to auto launch at start up.
   void SetAutoLaunchApp(const std::string& app_id,
-                        OwnerSettingsServiceChromeOS* service);
+                        OwnerSettingsServiceAsh* service);
 
   // Returns true if there is a pending auto-launch request.
   bool IsAutoLaunchRequested() const;
@@ -144,9 +144,8 @@
 
   // Adds/removes a kiosk app by id. When removed, all locally cached data
   // will be removed as well.
-  void AddApp(const std::string& app_id, OwnerSettingsServiceChromeOS* service);
-  void RemoveApp(const std::string& app_id,
-                 OwnerSettingsServiceChromeOS* service);
+  void AddApp(const std::string& app_id, OwnerSettingsServiceAsh* service);
+  void RemoveApp(const std::string& app_id, OwnerSettingsServiceAsh* service);
 
   // KioskAppManagerBase:
   // Gets info of all apps that have no meta data load error.
diff --git a/chrome/browser/ash/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_app_manager_browsertest.cc
index 55251b6..69cdfe2 100644
--- a/chrome/browser/ash/app_mode/kiosk_app_manager_browsertest.cc
+++ b/chrome/browser/ash/app_mode/kiosk_app_manager_browsertest.cc
@@ -117,14 +117,9 @@
   }
 
   std::string err;
-  scoped_refptr<extensions::Extension> app =
-      extensions::Extension::Create(
-          base::FilePath(),
-          extensions::Manifest::INTERNAL,
-          value,
-          extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
-          id,
-          &err);
+  scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
+      base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
+      extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
   EXPECT_EQ(err, "");
   return app;
 }
diff --git a/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc b/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc
index e1ffe76..b5b661f 100644
--- a/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc
+++ b/chrome/browser/ash/app_mode/kiosk_crash_restore_browsertest.cc
@@ -15,7 +15,7 @@
 #include "chrome/browser/ash/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/login/test/kiosk_test_helpers.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/browser/extensions/browsertest_util.h"
@@ -67,8 +67,8 @@
 
   void SetUpInProcessBrowserTestFixture() override {
     // Override device policy.
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
 
diff --git a/chrome/browser/ash/arc/OWNERS b/chrome/browser/ash/arc/OWNERS
new file mode 100644
index 0000000..02d6b48
--- /dev/null
+++ b/chrome/browser/ash/arc/OWNERS
@@ -0,0 +1 @@
+file://components/arc/OWNERS
diff --git a/chrome/browser/ash/arc/PRESUBMIT.py b/chrome/browser/ash/arc/PRESUBMIT.py
new file mode 100644
index 0000000..72fada88
--- /dev/null
+++ b/chrome/browser/ash/arc/PRESUBMIT.py
@@ -0,0 +1,12 @@
+# Copyright 2017 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.
+
+def CheckChangeOnUpload(input_api, output_api):
+  # Apply the same PRESUBMIT for components/arc.
+  presubmit_path = (
+      input_api.change.RepositoryRoot() + '/components/arc/PRESUBMIT.py')
+  presubmit_content = input_api.ReadFile(presubmit_path)
+  global_vars = {}
+  exec(presubmit_content, global_vars)
+  return global_vars['CheckChangeOnUpload'](input_api, output_api)
diff --git a/chrome/browser/chromeos/arc/accessibility/DIR_METADATA b/chrome/browser/ash/arc/accessibility/DIR_METADATA
similarity index 100%
rename from chrome/browser/chromeos/arc/accessibility/DIR_METADATA
rename to chrome/browser/ash/arc/accessibility/DIR_METADATA
diff --git a/chrome/browser/chromeos/arc/accessibility/OWNERS b/chrome/browser/ash/arc/accessibility/OWNERS
similarity index 100%
rename from chrome/browser/chromeos/arc/accessibility/OWNERS
rename to chrome/browser/ash/arc/accessibility/OWNERS
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.cc b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.cc
similarity index 92%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.cc
rename to chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.cc
index a6f22a8e..04da4f6 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.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/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
 
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
-#include "chrome/browser/chromeos/arc/accessibility/geometry_util.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/geometry_util.h"
 #include "components/exo/wm_helper.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/views/widget/widget.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h
similarity index 89%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h
rename to chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h
index d723993f5..e660a5d 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h
+++ b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.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_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
 
 #include "components/arc/mojom/accessibility_helper.mojom.h"
 
@@ -64,4 +64,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_INFO_DATA_WRAPPER_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
rename to chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.cc
index 0824456..e87d4d7a 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
 
 #include <algorithm>
 
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h
similarity index 91%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h
rename to chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h
index 5db4a8f..97204f1 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h
+++ b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
 
 #include <string>
 #include <vector>
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_node_data.h"
 
@@ -103,4 +103,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_NODE_INFO_DATA_WRAPPER_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc
rename to chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc
index 1009547..389418f 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
 
 #include <map>
 #include <memory>
 #include <utility>
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#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 "chrome/grit/generated_resources.h"
 #include "components/arc/mojom/accessibility_helper.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.cc b/chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.cc
similarity index 96%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.cc
rename to chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.cc
index ce99209..e9a6d24 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.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/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
 
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.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/wm_helper.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h b/chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h
similarity index 85%
rename from chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h
rename to chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h
index 4eb1c4a..7026b834 100644
--- a/chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h
+++ b/chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
 
 #include <string>
 #include <vector>
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
 #include "ui/accessibility/ax_node_data.h"
 
 namespace arc {
@@ -59,4 +59,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ACCESSIBILITY_WINDOW_INFO_DATA_WRAPPER_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
similarity index 99%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.cc
index bae54fe..7b43b14d5 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.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/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 
 #include <utility>
 
@@ -15,8 +15,8 @@
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram_functions.h"
 #include "chrome/browser/ash/accessibility/magnification_manager.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/geometry_util.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/geometry_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/common/extensions/api/accessibility_private.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h
similarity index 95%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h
index 78ec33b0..cf28a31 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.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_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
 
 #include <map>
 #include <memory>
@@ -13,7 +13,7 @@
 
 #include "ash/public/cpp/external_arc/message_center/arc_notification_surface_manager.h"
 #include "chrome/browser/ash/accessibility/accessibility_manager.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 #include "chrome/browser/chromeos/arc/input_method_manager/arc_input_method_manager_service.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "components/arc/mojom/accessibility_helper.mojom-forward.h"
@@ -200,4 +200,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_HELPER_BRIDGE_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
index c02fb669..e08adff 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.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/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 
 #include <memory>
 #include <utility>
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
similarity index 99%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 775ea2dff..742d488 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.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/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 
 #include <memory>
 #include <unordered_map>
@@ -23,8 +23,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 #include "chrome/common/extensions/api/accessibility_private.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h b/chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h
similarity index 91%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h
index 7d4afc1..5f2fe4a 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_test_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_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
 
 #include "base/containers/flat_map.h"
 #include "base/optional.h"
@@ -80,4 +80,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_TEST_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_util.cc
similarity index 97%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.cc
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_util.cc
index 23cc19d5..3c611f2 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_util.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/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 
 #include "ash/public/cpp/app_types.h"
 #include "base/optional.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
 #include "components/arc/mojom/accessibility_helper.mojom.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/aura/window.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h b/chrome/browser/ash/arc/accessibility/arc_accessibility_util.h
similarity index 92%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_util.h
index 6bc92ac1..d8393e0 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_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_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
 
 #include <stdint.h>
 #include <string>
@@ -105,4 +105,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_ARC_ACCESSIBILITY_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util_unittest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_util_unittest.cc
similarity index 93%
rename from chrome/browser/chromeos/arc/accessibility/arc_accessibility_util_unittest.cc
rename to chrome/browser/ash/arc/accessibility/arc_accessibility_util_unittest.cc
index 02ee263..cdda80ab 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_util_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_util_unittest.cc
@@ -5,8 +5,8 @@
 #include <memory>
 
 #include "base/optional.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 #include "components/arc/mojom/accessibility_helper.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler.cc b/chrome/browser/ash/arc/accessibility/auto_complete_handler.cc
similarity index 93%
rename from chrome/browser/chromeos/arc/accessibility/auto_complete_handler.cc
rename to chrome/browser/ash/arc/accessibility/auto_complete_handler.cc
index a3743e9..7385c6d7 100644
--- a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler.cc
+++ b/chrome/browser/ash/arc/accessibility/auto_complete_handler.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/chromeos/arc/accessibility/auto_complete_handler.h"
+#include "chrome/browser/ash/arc/accessibility/auto_complete_handler.h"
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 #include "components/arc/mojom/accessibility_helper.mojom-forward.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler.h b/chrome/browser/ash/arc/accessibility/auto_complete_handler.h
similarity index 78%
rename from chrome/browser/chromeos/arc/accessibility/auto_complete_handler.h
rename to chrome/browser/ash/arc/accessibility/auto_complete_handler.h
index 85598be..4eecccdc 100644
--- a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler.h
+++ b/chrome/browser/ash/arc/accessibility/auto_complete_handler.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
 
 #include <memory>
 #include <utility>
 #include <vector>
 
 #include "base/optional.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 
 namespace ui {
 struct AXNodeData;
@@ -46,4 +46,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AUTO_COMPLETE_HANDLER_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler_unittest.cc b/chrome/browser/ash/arc/accessibility/auto_complete_handler_unittest.cc
similarity index 95%
rename from chrome/browser/chromeos/arc/accessibility/auto_complete_handler_unittest.cc
rename to chrome/browser/ash/arc/accessibility/auto_complete_handler_unittest.cc
index 550576a0..beeddb1b 100644
--- a/chrome/browser/chromeos/arc/accessibility/auto_complete_handler_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/auto_complete_handler_unittest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/arc/accessibility/auto_complete_handler.h"
+#include "chrome/browser/ash/arc/accessibility/auto_complete_handler.h"
 
 #include <map>
 #include <memory>
 #include <utility>
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#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/arc/mojom/accessibility_helper.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc.cc
similarity index 97%
rename from chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
rename to chrome/browser/ash/arc/accessibility/ax_tree_source_arc.cc
index 6ad689f..e9593fe 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc.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/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 
 #include <stack>
 #include <string>
@@ -10,11 +10,11 @@
 
 #include "ash/public/cpp/external_arc/message_center/arc_notification_surface.h"
 #include "ash/public/cpp/external_arc/message_center/arc_notification_surface_manager.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/auto_complete_handler.h"
-#include "chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/auto_complete_handler.h"
+#include "chrome/browser/ash/arc/accessibility/drawer_layout_handler.h"
 #include "components/exo/input_method_surface.h"
 #include "components/exo/wm_helper.h"
 #include "extensions/browser/api/automation_internal/automation_event_router.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h
similarity index 96%
rename from chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h
rename to chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h
index e00c1f3..810e37a 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h
+++ b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc.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_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
 
 #include <map>
 #include <memory>
@@ -12,7 +12,7 @@
 #include <vector>
 
 #include "base/containers/flat_map.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
 #include "components/arc/mojom/accessibility_helper.mojom-forward.h"
 #include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "ui/accessibility/ax_action_handler.h"
@@ -213,4 +213,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_AX_TREE_SOURCE_ARC_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
rename to chrome/browser/ash/arc/accessibility/ax_tree_source_arc_unittest.cc
index ec45a88..86f330e 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/ax_tree_source_arc_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 
 #include <utility>
 
 #include "base/optional.h"
 #include "base/stl_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 #include "components/arc/mojom/accessibility_helper.mojom.h"
 #include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.cc b/chrome/browser/ash/arc/accessibility/drawer_layout_handler.cc
similarity index 88%
rename from chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.cc
rename to chrome/browser/ash/arc/accessibility/drawer_layout_handler.cc
index 5d511c7..e65afcf 100644
--- a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.cc
+++ b/chrome/browser/ash/arc/accessibility/drawer_layout_handler.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/chromeos/arc/accessibility/drawer_layout_handler.h"
+#include "chrome/browser/ash/arc/accessibility/drawer_layout_handler.h"
 
 #include "base/strings/string_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 #include "components/arc/mojom/accessibility_helper.mojom-forward.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.h b/chrome/browser/ash/arc/accessibility/drawer_layout_handler.h
similarity index 76%
rename from chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.h
rename to chrome/browser/ash/arc/accessibility/drawer_layout_handler.h
index 5b656d1..86abe5a 100644
--- a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.h
+++ b/chrome/browser/ash/arc/accessibility/drawer_layout_handler.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
 
 #include <memory>
 #include <string>
 #include <utility>
 
 #include "base/optional.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
 
 namespace ui {
 struct AXNodeData;
@@ -43,4 +43,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_DRAWER_LAYOUT_HANDLER_H_
diff --git a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler_unittest.cc b/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
similarity index 90%
rename from chrome/browser/chromeos/arc/accessibility/drawer_layout_handler_unittest.cc
rename to chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
index 10907b1..f4584def 100644
--- a/chrome/browser/chromeos/arc/accessibility/drawer_layout_handler_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/drawer_layout_handler_unittest.cc
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/arc/accessibility/drawer_layout_handler.h"
+#include "chrome/browser/ash/arc/accessibility/drawer_layout_handler.h"
 
 #include <map>
 #include <memory>
 #include <utility>
 
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_test_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_node_info_data_wrapper.h"
+#include "chrome/browser/ash/arc/accessibility/accessibility_window_info_data_wrapper.h"
+#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/arc/mojom/accessibility_helper.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/geometry_util.cc b/chrome/browser/ash/arc/accessibility/geometry_util.cc
similarity index 95%
rename from chrome/browser/chromeos/arc/accessibility/geometry_util.cc
rename to chrome/browser/ash/arc/accessibility/geometry_util.cc
index dd775eb3..69e6531c 100644
--- a/chrome/browser/chromeos/arc/accessibility/geometry_util.cc
+++ b/chrome/browser/ash/arc/accessibility/geometry_util.cc
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
 #define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
 
-#include "chrome/browser/chromeos/arc/accessibility/geometry_util.h"
+#include "chrome/browser/ash/arc/accessibility/geometry_util.h"
 
 #include "components/exo/wm_helper.h"
 #include "ui/aura/window.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/geometry_util.h b/chrome/browser/ash/arc/accessibility/geometry_util.h
similarity index 78%
rename from chrome/browser/chromeos/arc/accessibility/geometry_util.h
rename to chrome/browser/ash/arc/accessibility/geometry_util.h
index 24ccb4a..e67d692a 100644
--- a/chrome/browser/chromeos/arc/accessibility/geometry_util.h
+++ b/chrome/browser/ash/arc/accessibility/geometry_util.h
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
+#define CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
 
 // TODO(hirokisato): support multiple display.
 
 namespace gfx {
+class Rect;
 class RectF;
 }
 
@@ -26,4 +27,4 @@
 int GetChromeWindowHeightOffsetInDip(aura::Window* window);
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ACCESSIBILITY_GEOMETRY_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.cc b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.cc
rename to chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.cc
index 5e715687..623e464 100644
--- a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.cc
+++ b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.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/chromeos/arc/adbd/arc_adbd_monitor_bridge.h"
+#include "chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.h"
 
 #include <stdint.h>
 
diff --git a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.h b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.h
similarity index 92%
rename from chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.h
rename to chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.h
index 90764f0..9c2398f7 100644
--- a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.h
+++ b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.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_CHROMEOS_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
+#ifndef CHROME_BROWSER_ASH_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
+#define CHROME_BROWSER_ASH_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
 
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
@@ -67,4 +67,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
+#endif  // CHROME_BROWSER_ASH_ARC_ADBD_ARC_ADBD_MONITOR_BRIDGE_H_
diff --git a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge_unittest.cc b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge_unittest.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge_unittest.cc
rename to chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge_unittest.cc
index 4f93c04..f32da51 100644
--- a/chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge_unittest.cc
+++ b/chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge_unittest.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/chromeos/arc/adbd/arc_adbd_monitor_bridge.h"
+#include "chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.h"
 
 #include <memory>
 
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/OWNERS b/chrome/browser/ash/arc/app_shortcuts/OWNERS
similarity index 100%
rename from chrome/browser/chromeos/arc/app_shortcuts/OWNERS
rename to chrome/browser/ash/arc/app_shortcuts/OWNERS
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.cc b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.cc
similarity index 83%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.cc
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.cc
index f471746..7dc3656 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.cc
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.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/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 
 namespace arc {
 
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h
similarity index 82%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h
index f6b51a8f..9f65b63 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.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_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
+#ifndef CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
+#define CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
 
 #include <string>
 #include <vector>
@@ -40,4 +40,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
+#endif  // CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUT_ITEM_H_
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc
similarity index 96%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc
index b90d605..ee35df4a3 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.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/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
 
 #include <tuple>
 #include <utility>
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h
similarity index 85%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h
index cbd61383..9ee22c05 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.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_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
+#define CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
 
 #include <memory>
 #include <string>
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 
 class Profile;
 
@@ -68,4 +68,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_MENU_BUILDER_H_
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc
similarity index 96%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc
index 741cff0..9c0d4cc7 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.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/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
 
 #include <memory>
 #include <utility>
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.cc b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.cc
similarity index 93%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.cc
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.cc
index 0e17646..173e7ed 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.cc
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.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/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h"
 
 #include <string>
 #include <utility>
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
+#include "chrome/browser/apps/app_service/menu_util.h"
 #include "chrome/browser/chromeos/arc/icon_decode_request.h"
 #include "chrome/common/chrome_features.h"
 #include "components/arc/arc_service_manager.h"
@@ -70,7 +71,6 @@
       base::BindOnce(&ArcAppShortcutsRequest::OnAllIconDecodeRequestsDone,
                      base::Unretained(this)));
 
-  constexpr int kAppShortcutIconSize = 32;
   for (const auto& shortcut_item_ptr : shortcut_items) {
     ArcAppShortcutItem item;
     item.shortcut_id = shortcut_item_ptr->shortcut_id;
@@ -81,7 +81,7 @@
 
     if (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon)) {
       apps::ArcRawIconPngDataToImageSkia(
-          std::move(shortcut_item_ptr->icon), kAppShortcutIconSize,
+          std::move(shortcut_item_ptr->icon), apps::kAppShortcutIconSizeDip,
           base::BindOnce(&ArcAppShortcutsRequest::OnSingleIconDecodeRequestDone,
                          weak_ptr_factory_.GetWeakPtr(), items_->size() - 1));
       continue;
@@ -94,7 +94,7 @@
       icon_decode_requests_.emplace_back(std::make_unique<IconDecodeRequest>(
           base::BindOnce(&ArcAppShortcutsRequest::OnSingleIconDecodeRequestDone,
                          weak_ptr_factory_.GetWeakPtr(), items_->size() - 1),
-          kAppShortcutIconSize));
+          apps::kAppShortcutIconSizeDip));
       icon_decode_requests_.back()->StartWithOptions(
           shortcut_item_ptr->icon_png);
       continue;
@@ -103,7 +103,7 @@
     icon_decode_requests_.emplace_back(std::make_unique<IconDecodeRequest>(
         base::BindOnce(&ArcAppShortcutsRequest::OnSingleIconDecodeRequestDone,
                        weak_ptr_factory_.GetWeakPtr(), items_->size() - 1),
-        kAppShortcutIconSize));
+        apps::kAppShortcutIconSizeDip));
     icon_decode_requests_.back()->StartWithOptions(
         shortcut_item_ptr->icon->icon_png_data.value());
   }
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h
similarity index 85%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h
index a57c1e5..34233b1 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.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_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
+#ifndef CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
+#define CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
 
 #include <memory>
 #include <vector>
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 #include "components/arc/mojom/app.mojom-forward.h"
 
 namespace arc {
@@ -63,4 +63,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
+#endif  // CHROME_BROWSER_ASH_ARC_APP_SHORTCUTS_ARC_APP_SHORTCUTS_REQUEST_H_
diff --git a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc
similarity index 92%
rename from chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc
rename to chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc
index df9ef5f0..76d3435 100644
--- a/chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc
+++ b/chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request_unittest.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/chromeos/arc/app_shortcuts/arc_app_shortcuts_request.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_request.h"
 
 #include <memory>
 #include <utility>
@@ -12,7 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 #include "chrome/browser/chromeos/arc/icon_decode_request.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
 #include "chrome/test/base/testing_profile.h"
diff --git a/chrome/browser/chromeos/arc/auth/OWNERS b/chrome/browser/ash/arc/auth/OWNERS
similarity index 100%
rename from chrome/browser/chromeos/arc/auth/OWNERS
rename to chrome/browser/ash/arc/auth/OWNERS
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
rename to chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
index 5327c02..a3786dc 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.cc
+++ b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.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/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
 
 #include <string>
 #include <utility>
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h
similarity index 91%
rename from chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h
rename to chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h
index 2c9ef2f..58b4fae 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h
+++ b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.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_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
 
 #include <memory>
 #include <string>
@@ -11,8 +11,8 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ash/arc/auth/arc_fetcher_base.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
-#include "chrome/browser/chromeos/arc/auth/arc_fetcher_base.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 
@@ -103,4 +103,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_ACTIVE_DIRECTORY_ENROLLMENT_TOKEN_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
similarity index 99%
rename from chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
rename to chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
index 67498b4..a582f1b 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -11,10 +11,10 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
+#include "chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
-#include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
 #include "chrome/browser/chromeos/arc/extensions/fake_arc_support.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/dm_token_storage.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h b/chrome/browser/ash/arc/auth/arc_auth_code_fetcher.h
similarity index 80%
rename from chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h
rename to chrome/browser/ash/arc/auth/arc_auth_code_fetcher.h
index 5205f1d..b10524d 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h
+++ b/chrome/browser/ash/arc/auth/arc_auth_code_fetcher.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
 
 #include <string>
 
 #include "base/callback.h"
-#include "chrome/browser/chromeos/arc/auth/arc_fetcher_base.h"
+#include "chrome/browser/ash/arc/auth/arc_fetcher_base.h"
 
 namespace arc {
 
@@ -32,4 +32,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc b/chrome/browser/ash/arc/auth/arc_auth_context.cc
similarity index 97%
rename from chrome/browser/chromeos/arc/auth/arc_auth_context.cc
rename to chrome/browser/ash/arc/auth/arc_auth_context.cc
index b3705ad..2eac653 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_context.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/chromeos/arc/auth/arc_auth_context.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_context.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_context.h b/chrome/browser/ash/arc/auth/arc_auth_context.h
similarity index 92%
rename from chrome/browser/chromeos/arc/auth/arc_auth_context.h
rename to chrome/browser/ash/arc/auth/arc_auth_context.h
index cdfdbbd..a225f37 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_context.h
+++ b/chrome/browser/ash/arc/auth/arc_auth_context.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_CHROMEOS_ARC_AUTH_ARC_AUTH_CONTEXT_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CONTEXT_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CONTEXT_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CONTEXT_H_
 
 #include <memory>
 #include <string>
@@ -66,4 +66,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_CONTEXT_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_CONTEXT_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/ash/arc/auth/arc_auth_service.cc
similarity index 99%
rename from chrome/browser/chromeos/arc/auth/arc_auth_service.cc
rename to chrome/browser/ash/arc/auth/arc_auth_service.cc
index 7a2ca18..0498dfe1 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service.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/chromeos/arc/auth/arc_auth_service.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
 
 #include <utility>
 #include <vector>
@@ -16,12 +16,12 @@
 #include "chrome/browser/account_manager_facade_factory.h"
 #include "chrome/browser/ash/account_manager/account_manager_migrator.h"
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
+#include "chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/ash/login/demo_mode/demo_session.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h"
-#include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/arc/session/arc_provisioning_result.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.h b/chrome/browser/ash/arc/auth/arc_auth_service.h
similarity index 96%
rename from chrome/browser/chromeos/arc/auth/arc_auth_service.h
rename to chrome/browser/ash/arc/auth/arc_auth_service.h
index cf476e7..6436715 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.h
+++ b/chrome/browser/ash/arc/auth/arc_auth_service.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_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_SERVICE_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_SERVICE_H_
 
 #include <memory>
 #include <string>
@@ -14,7 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
-#include "chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager_observer.h"
 #include "components/arc/mojom/auth.mojom.h"
 #include "components/arc/session/connection_observer.h"
@@ -206,4 +206,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_AUTH_SERVICE_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_AUTH_SERVICE_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
similarity index 99%
rename from chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
rename to chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
index 9c73da0..90e7db5 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_auth_service_browsertest.cc
@@ -17,6 +17,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_context.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
+#include "chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h"
 #include "chrome/browser/ash/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/ash/certificate_provider/certificate_provider_service_factory.h"
 #include "chrome/browser/ash/login/demo_mode/demo_session.h"
@@ -25,9 +28,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_context.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
-#include "chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/session/arc_service_launcher.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/test/test_arc_session_manager.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
rename to chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.cc
index 538640fb3..e0f5d7b5 100644
--- a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.cc
+++ b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.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/chromeos/arc/auth/arc_background_auth_code_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h"
 
 #include <utility>
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h
similarity index 88%
rename from chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
rename to chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h
index f71e94e..0500f0ba 100644
--- a/chrome/browser/chromeos/arc/auth/arc_background_auth_code_fetcher.h
+++ b/chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.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_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
 
 #include <memory>
 #include <string>
@@ -11,9 +11,9 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_code_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_context.h"
 #include "chrome/browser/chromeos/arc/arc_optin_uma.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_context.h"
 
 class Profile;
 
@@ -91,4 +91,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_BACKGROUND_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_fetcher_base.cc b/chrome/browser/ash/arc/auth/arc_fetcher_base.cc
similarity index 87%
rename from chrome/browser/chromeos/arc/auth/arc_fetcher_base.cc
rename to chrome/browser/ash/arc/auth/arc_fetcher_base.cc
index 47e7829..8e352ce 100644
--- a/chrome/browser/chromeos/arc/auth/arc_fetcher_base.cc
+++ b/chrome/browser/ash/arc/auth/arc_fetcher_base.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/chromeos/arc/auth/arc_fetcher_base.h"
+#include "chrome/browser/ash/arc/auth/arc_fetcher_base.h"
 
 namespace arc {
 
diff --git a/chrome/browser/chromeos/arc/auth/arc_fetcher_base.h b/chrome/browser/ash/arc/auth/arc_fetcher_base.h
similarity index 81%
rename from chrome/browser/chromeos/arc/auth/arc_fetcher_base.h
rename to chrome/browser/ash/arc/auth/arc_fetcher_base.h
index d6b606f0..819bc62 100644
--- a/chrome/browser/chromeos/arc/auth/arc_fetcher_base.h
+++ b/chrome/browser/ash/arc/auth/arc_fetcher_base.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_CHROMEOS_ARC_AUTH_ARC_FETCHER_BASE_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_FETCHER_BASE_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_FETCHER_BASE_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_FETCHER_BASE_H_
 
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -32,4 +32,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_FETCHER_BASE_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_FETCHER_BASE_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.cc
similarity index 97%
rename from chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
rename to chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.cc
index 402baf4..59092d5f 100644
--- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.cc
+++ b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.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/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h"
 
 #include <string>
 #include <utility>
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h
similarity index 82%
rename from chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h
rename to chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h
index 56f547e..162f2294 100644
--- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h
+++ b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
-#define CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
+#ifndef CHROME_BROWSER_ASH_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
+#define CHROME_BROWSER_ASH_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
 
 #include <memory>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_code_fetcher.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_code_fetcher.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/device_management_service.h"
 
@@ -46,4 +46,4 @@
 
 }  // namespace arc
 
-#endif  // CHROME_BROWSER_CHROMEOS_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
+#endif  // CHROME_BROWSER_ASH_ARC_AUTH_ARC_ROBOT_AUTH_CODE_FETCHER_H_
diff --git a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
similarity index 98%
rename from chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
rename to chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
index ea620318..d6a1d04 100644
--- a/chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
+++ b/chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc
@@ -12,11 +12,11 @@
 #include "base/run_loop.h"
 #include "base/task/post_task.h"
 #include "base/test/bind.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
+#include "chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
-#include "chrome/browser/chromeos/arc/auth/arc_robot_auth_code_fetcher.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ash/crosapi/automation_ash.cc b/chrome/browser/ash/crosapi/automation_ash.cc
index d393f05d..71137daa 100644
--- a/chrome/browser/ash/crosapi/automation_ash.cc
+++ b/chrome/browser/ash/crosapi/automation_ash.cc
@@ -12,7 +12,6 @@
 #include "components/version_info/channel.h"
 #include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "extensions/common/extension_messages.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
diff --git a/chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.cc b/chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.cc
index eecd077..165e502 100644
--- a/chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.cc
+++ b/chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.h"
 
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "components/ownership/owner_key_util.h"
@@ -38,9 +38,9 @@
                                         LoginState::LOGGED_IN_USER_NONE);
   }
 
-  OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync(
+  OwnerSettingsServiceAsh::IsOwnerForSafeModeAsync(
       context.GetUserIDHash(),
-      OwnerSettingsServiceChromeOSFactory::GetInstance()->GetOwnerKeyUtil(),
+      OwnerSettingsServiceAshFactory::GetInstance()->GetOwnerKeyUtil(),
       std::move(callback));
 }
 
diff --git a/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc b/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
index b965a4c..6c5bf5e 100644
--- a/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
+++ b/chrome/browser/ash/login/auth/cryptohome_authenticator_unittest.cc
@@ -20,8 +20,8 @@
 #include "base/strings/string_util.h"
 #include "chrome/browser/ash/login/auth/chrome_cryptohome_authenticator.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
@@ -266,8 +266,8 @@
     // user_manager_enabler_, because it will create another UserManager
     // instance if UserManager instance has not been registed before.
     profile_.reset(new TestingProfile);
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
     Key key("fakepass");
     key.SetLabel(kCryptohomeGaiaKeyLabel);
     user_context_.SetKey(key);
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
index b9917f1..746209ea 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_browsertest.cc
@@ -35,7 +35,7 @@
 #include "chrome/browser/ash/login/users/chrome_user_manager.h"
 #include "chrome/browser/ash/login/users/default_user_image/default_user_images.h"
 #include "chrome/browser/ash/login/users/mock_user_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -554,8 +554,8 @@
   // UserImageManagerTest overrides:
   void SetUpInProcessBrowserTestFixture() override {
     device_policy_.Build();
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
     // Override FakeSessionManagerClient. This will be shut down by the browser.
diff --git a/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc b/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
index 060f2e89..aceb2c34 100644
--- a/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
+++ b/chrome/browser/ash/login/users/wallpaper_policy_browsertest.cc
@@ -29,7 +29,7 @@
 #include "chrome/browser/ash/login/test/fake_gaia_mixin.h"
 #include "chrome/browser/ash/login/test/login_manager_mixin.h"
 #include "chrome/browser/ash/login/ui/login_display_host.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
@@ -163,8 +163,8 @@
   // LoginManagerTest:
   void SetUpInProcessBrowserTestFixture() override {
     device_policy_.Build();
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
     SessionManagerClient::InitializeFakeInMemory();
diff --git a/chrome/browser/ash/ownership/fake_owner_settings_service.cc b/chrome/browser/ash/ownership/fake_owner_settings_service.cc
index 88e685f9..397114c5 100644
--- a/chrome/browser/ash/ownership/fake_owner_settings_service.cc
+++ b/chrome/browser/ash/ownership/fake_owner_settings_service.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ash/ownership/fake_owner_settings_service.h"
 
 #include "base/check.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chromeos/tpm/install_attributes.h"
 #include "components/ownership/mock_owner_key_util.h"
@@ -15,11 +15,10 @@
 FakeOwnerSettingsService::FakeOwnerSettingsService(
     StubCrosSettingsProvider* provider,
     Profile* profile)
-    : OwnerSettingsServiceChromeOS(
+    : OwnerSettingsServiceAsh(
           /* device_settings_service= */ nullptr,
           profile,
-          OwnerSettingsServiceChromeOSFactory::GetInstance()
-              ->GetOwnerKeyUtil()),
+          OwnerSettingsServiceAshFactory::GetInstance()->GetOwnerKeyUtil()),
       set_management_settings_result_(true),
       settings_provider_(provider) {}
 
@@ -27,7 +26,7 @@
     StubCrosSettingsProvider* provider,
     Profile* profile,
     const scoped_refptr<ownership::OwnerKeyUtil>& owner_key_util)
-    : OwnerSettingsServiceChromeOS(nullptr, profile, owner_key_util),
+    : OwnerSettingsServiceAsh(nullptr, profile, owner_key_util),
       set_management_settings_result_(true),
       settings_provider_(provider) {}
 
diff --git a/chrome/browser/ash/ownership/fake_owner_settings_service.h b/chrome/browser/ash/ownership/fake_owner_settings_service.h
index 50e00e90..ad869d0 100644
--- a/chrome/browser/ash/ownership/fake_owner_settings_service.h
+++ b/chrome/browser/ash/ownership/fake_owner_settings_service.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 
 class Profile;
 
@@ -19,7 +19,7 @@
 
 class StubCrosSettingsProvider;
 
-class FakeOwnerSettingsService : public OwnerSettingsServiceChromeOS {
+class FakeOwnerSettingsService : public OwnerSettingsServiceAsh {
  public:
   FakeOwnerSettingsService(StubCrosSettingsProvider* provider,
                            Profile* profile);
@@ -38,7 +38,7 @@
     return last_settings_;
   }
 
-  // OwnerSettingsServiceChromeOS:
+  // OwnerSettingsServiceAsh:
   bool IsOwner() override;
   bool Set(const std::string& setting, const base::Value& value) override;
 
diff --git a/chrome/browser/ash/ownership/owner_settings_service_chromeos.cc b/chrome/browser/ash/ownership/owner_settings_service_ash.cc
similarity index 90%
rename from chrome/browser/ash/ownership/owner_settings_service_chromeos.cc
rename to chrome/browser/ash/ownership/owner_settings_service_ash.cc
index e6bbe49..4718ac4f 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_chromeos.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.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/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 
 #include <keyhi.h>
 #include <stdint.h>
@@ -24,7 +24,7 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_checker.h"
 #include "chrome/browser/ash/login/session/user_session_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_provider.h"
@@ -168,7 +168,7 @@
 // not. Responds via |callback|.
 void DoesPrivateKeyExistAsync(
     const scoped_refptr<OwnerKeyUtil>& owner_key_util,
-    OwnerSettingsServiceChromeOS::IsOwnerCallback callback) {
+    OwnerSettingsServiceAsh::IsOwnerCallback callback) {
   if (!owner_key_util.get()) {
     std::move(callback).Run(false);
     return;
@@ -185,13 +185,11 @@
 
 }  // namespace
 
-OwnerSettingsServiceChromeOS::ManagementSettings::ManagementSettings() =
-    default;
+OwnerSettingsServiceAsh::ManagementSettings::ManagementSettings() = default;
 
-OwnerSettingsServiceChromeOS::ManagementSettings::~ManagementSettings() =
-    default;
+OwnerSettingsServiceAsh::ManagementSettings::~ManagementSettings() = default;
 
-OwnerSettingsServiceChromeOS::OwnerSettingsServiceChromeOS(
+OwnerSettingsServiceAsh::OwnerSettingsServiceAsh(
     DeviceSettingsService* device_settings_service,
     Profile* profile,
     const scoped_refptr<OwnerKeyUtil>& owner_key_util)
@@ -201,7 +199,7 @@
   if (chromeos::TPMTokenLoader::IsInitialized()) {
     chromeos::TPMTokenLoader::TPMTokenStatus tpm_token_status =
         chromeos::TPMTokenLoader::Get()->IsTPMTokenEnabled(
-            base::BindOnce(&OwnerSettingsServiceChromeOS::OnTPMTokenReady,
+            base::BindOnce(&OwnerSettingsServiceAsh::OnTPMTokenReady,
                            weak_factory_.GetWeakPtr()));
     waiting_for_tpm_token_ =
         tpm_token_status ==
@@ -221,14 +219,14 @@
   }
 
   UserSessionManager::GetInstance()->WaitForEasyUnlockKeyOpsFinished(
-      base::BindOnce(&OwnerSettingsServiceChromeOS::OnEasyUnlockKeyOpsFinished,
+      base::BindOnce(&OwnerSettingsServiceAsh::OnEasyUnlockKeyOpsFinished,
                      weak_factory_.GetWeakPtr()));
   // The ProfileManager may be null in unit tests.
   if (g_browser_process->profile_manager())
     g_browser_process->profile_manager()->AddObserver(this);
 }
 
-OwnerSettingsServiceChromeOS::~OwnerSettingsServiceChromeOS() {
+OwnerSettingsServiceAsh::~OwnerSettingsServiceAsh() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // The ProfileManager may be null in unit tests.
@@ -242,18 +240,17 @@
     chromeos::SessionManagerClient::Get()->RemoveObserver(this);
 }
 
-OwnerSettingsServiceChromeOS* OwnerSettingsServiceChromeOS::FromWebUI(
+OwnerSettingsServiceAsh* OwnerSettingsServiceAsh::FromWebUI(
     content::WebUI* web_ui) {
   if (!web_ui)
     return nullptr;
   Profile* profile = Profile::FromWebUI(web_ui);
   if (!profile)
     return nullptr;
-  return OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile);
+  return OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
 }
 
-void OwnerSettingsServiceChromeOS::OnTPMTokenReady(
-    bool /* tpm_token_enabled */) {
+void OwnerSettingsServiceAsh::OnTPMTokenReady(bool /* tpm_token_enabled */) {
   DCHECK(thread_checker_.CalledOnValidThread());
   waiting_for_tpm_token_ = false;
 
@@ -262,26 +259,26 @@
   ReloadKeypair();
 }
 
-void OwnerSettingsServiceChromeOS::OnEasyUnlockKeyOpsFinished() {
+void OwnerSettingsServiceAsh::OnEasyUnlockKeyOpsFinished() {
   DCHECK(thread_checker_.CalledOnValidThread());
   waiting_for_easy_unlock_operation_finshed_ = false;
 
   ReloadKeypair();
 }
 
-bool OwnerSettingsServiceChromeOS::HasPendingChanges() const {
+bool OwnerSettingsServiceAsh::HasPendingChanges() const {
   return !pending_changes_.empty() || tentative_settings_.get() ||
          has_pending_fixups_;
 }
 
-bool OwnerSettingsServiceChromeOS::IsOwner() {
+bool OwnerSettingsServiceAsh::IsOwner() {
   if (chromeos::InstallAttributes::Get()->IsEnterpriseManaged()) {
     return false;
   }
   return OwnerSettingsService::IsOwner();
 }
 
-void OwnerSettingsServiceChromeOS::IsOwnerAsync(IsOwnerCallback callback) {
+void OwnerSettingsServiceAsh::IsOwnerAsync(IsOwnerCallback callback) {
   if (chromeos::InstallAttributes::Get()->IsEnterpriseManaged()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), false));
@@ -290,12 +287,12 @@
   OwnerSettingsService::IsOwnerAsync(std::move(callback));
 }
 
-bool OwnerSettingsServiceChromeOS::HandlesSetting(const std::string& setting) {
+bool OwnerSettingsServiceAsh::HandlesSetting(const std::string& setting) {
   return DeviceSettingsProvider::IsDeviceSetting(setting);
 }
 
-bool OwnerSettingsServiceChromeOS::Set(const std::string& setting,
-                                       const base::Value& value) {
+bool OwnerSettingsServiceAsh::Set(const std::string& setting,
+                                  const base::Value& value) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (!IsOwner() && !IsOwnerInTests(user_id_))
     return false;
@@ -320,8 +317,8 @@
   return true;
 }
 
-bool OwnerSettingsServiceChromeOS::AppendToList(const std::string& setting,
-                                                const base::Value& value) {
+bool OwnerSettingsServiceAsh::AppendToList(const std::string& setting,
+                                           const base::Value& value) {
   DCHECK(thread_checker_.CalledOnValidThread());
   const base::Value* old_value = CrosSettings::Get()->GetPref(setting);
   if (old_value && !old_value->is_list())
@@ -333,8 +330,8 @@
   return Set(setting, *new_value);
 }
 
-bool OwnerSettingsServiceChromeOS::RemoveFromList(const std::string& setting,
-                                                  const base::Value& value) {
+bool OwnerSettingsServiceAsh::RemoveFromList(const std::string& setting,
+                                             const base::Value& value) {
   DCHECK(thread_checker_.CalledOnValidThread());
   const base::Value* old_value = CrosSettings::Get()->GetPref(setting);
   if (old_value && !old_value->is_list())
@@ -346,7 +343,7 @@
   return Set(setting, *new_value);
 }
 
-bool OwnerSettingsServiceChromeOS::CommitTentativeDeviceSettings(
+bool OwnerSettingsServiceAsh::CommitTentativeDeviceSettings(
     std::unique_ptr<enterprise_management::PolicyData> policy) {
   if (!IsOwner() && !IsOwnerInTests(user_id_))
     return false;
@@ -361,7 +358,7 @@
   return true;
 }
 
-void OwnerSettingsServiceChromeOS::OnProfileAdded(Profile* profile) {
+void OwnerSettingsServiceAsh::OnProfileAdded(Profile* profile) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (profile != profile_)
     return;
@@ -370,28 +367,28 @@
   ReloadKeypair();
 }
 
-void OwnerSettingsServiceChromeOS::OwnerKeySet(bool success) {
+void OwnerSettingsServiceAsh::OwnerKeySet(bool success) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (success)
     ReloadKeypair();
 }
 
-void OwnerSettingsServiceChromeOS::OwnershipStatusChanged() {
+void OwnerSettingsServiceAsh::OwnershipStatusChanged() {
   DCHECK(thread_checker_.CalledOnValidThread());
   StorePendingChanges();
 }
 
-void OwnerSettingsServiceChromeOS::DeviceSettingsUpdated() {
+void OwnerSettingsServiceAsh::DeviceSettingsUpdated() {
   DCHECK(thread_checker_.CalledOnValidThread());
   StorePendingChanges();
 }
 
-void OwnerSettingsServiceChromeOS::OnDeviceSettingsServiceShutdown() {
+void OwnerSettingsServiceAsh::OnDeviceSettingsServiceShutdown() {
   device_settings_service_ = nullptr;
 }
 
 // static
-void OwnerSettingsServiceChromeOS::IsOwnerForSafeModeAsync(
+void OwnerSettingsServiceAsh::IsOwnerForSafeModeAsync(
     const std::string& user_hash,
     const scoped_refptr<OwnerKeyUtil>& owner_key_util,
     IsOwnerCallback callback) {
@@ -409,7 +406,7 @@
 }
 
 // static
-std::unique_ptr<em::PolicyData> OwnerSettingsServiceChromeOS::AssemblePolicy(
+std::unique_ptr<em::PolicyData> OwnerSettingsServiceAsh::AssemblePolicy(
     const std::string& user_id,
     const em::PolicyData* policy_data,
     em::ChromeDeviceSettingsProto* settings) {
@@ -434,13 +431,13 @@
   if (policy->management_mode() == em::PolicyData::LOCAL_OWNER)
     FixupLocalOwnerPolicy(user_id, settings);
   if (!settings->SerializeToString(policy->mutable_policy_value()))
-    return std::unique_ptr<em::PolicyData>();
+    return nullptr;
 
   return policy;
 }
 
 // static
-void OwnerSettingsServiceChromeOS::FixupLocalOwnerPolicy(
+void OwnerSettingsServiceAsh::FixupLocalOwnerPolicy(
     const std::string& user_id,
     enterprise_management::ChromeDeviceSettingsProto* settings) {
   if (!settings->has_allow_new_users())
@@ -462,7 +459,7 @@
 }
 
 // static
-void OwnerSettingsServiceChromeOS::UpdateDeviceSettings(
+void OwnerSettingsServiceAsh::UpdateDeviceSettings(
     const std::string& path,
     const base::Value& value,
     enterprise_management::ChromeDeviceSettingsProto& settings) {
@@ -703,7 +700,7 @@
   }
 }
 
-void OwnerSettingsServiceChromeOS::OnPostKeypairLoadedActions() {
+void OwnerSettingsServiceAsh::OnPostKeypairLoadedActions() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   const user_manager::User* user =
@@ -717,7 +714,7 @@
   has_pending_fixups_ = true;
 }
 
-void OwnerSettingsServiceChromeOS::ReloadKeypairImpl(
+void OwnerSettingsServiceAsh::ReloadKeypairImpl(
     base::OnceCallback<void(const scoped_refptr<PublicKey>& public_key,
                             const scoped_refptr<PrivateKey>& private_key)>
         callback) {
@@ -741,7 +738,7 @@
                      std::move(callback)));
 }
 
-void OwnerSettingsServiceChromeOS::StorePendingChanges() {
+void OwnerSettingsServiceAsh::StorePendingChanges() {
   if (!HasPendingChanges() || store_settings_factory_.HasWeakPtrs() ||
       !device_settings_service_ || user_id_.empty() || !IsOwner()) {
     return;
@@ -772,13 +769,13 @@
       base::ThreadPool::CreateTaskRunner({base::MayBlock()});
   bool rv = AssembleAndSignPolicyAsync(
       task_runner.get(), std::move(policy),
-      base::BindOnce(&OwnerSettingsServiceChromeOS::OnPolicyAssembledAndSigned,
+      base::BindOnce(&OwnerSettingsServiceAsh::OnPolicyAssembledAndSigned,
                      store_settings_factory_.GetWeakPtr()));
   if (!rv)
     ReportStatusAndContinueStoring(false /* success */);
 }
 
-void OwnerSettingsServiceChromeOS::OnPolicyAssembledAndSigned(
+void OwnerSettingsServiceAsh::OnPolicyAssembledAndSigned(
     std::unique_ptr<em::PolicyFetchResponse> policy_response) {
   if (!policy_response.get() || !device_settings_service_) {
     ReportStatusAndContinueStoring(false /* success */);
@@ -786,26 +783,25 @@
   }
   device_settings_service_->Store(
       std::move(policy_response),
-      base::BindOnce(&OwnerSettingsServiceChromeOS::OnSignedPolicyStored,
+      base::BindOnce(&OwnerSettingsServiceAsh::OnSignedPolicyStored,
                      store_settings_factory_.GetWeakPtr(), true /* success */));
 }
 
-void OwnerSettingsServiceChromeOS::OnSignedPolicyStored(bool success) {
+void OwnerSettingsServiceAsh::OnSignedPolicyStored(bool success) {
   CHECK(device_settings_service_);
   ReportStatusAndContinueStoring(success &&
                                  device_settings_service_->status() ==
                                      DeviceSettingsService::STORE_SUCCESS);
 }
 
-void OwnerSettingsServiceChromeOS::ReportStatusAndContinueStoring(
-    bool success) {
+void OwnerSettingsServiceAsh::ReportStatusAndContinueStoring(bool success) {
   store_settings_factory_.InvalidateWeakPtrs();
   for (auto& observer : observers_)
     observer.OnSignedPolicyStored(success);
   StorePendingChanges();
 }
 
-void OwnerSettingsServiceChromeOS::MigrateFeatureFlags(
+void OwnerSettingsServiceAsh::MigrateFeatureFlags(
     enterprise_management::ChromeDeviceSettingsProto* settings) {
   DCHECK(IsOwner() || IsOwnerInTests(user_id_));
 
diff --git a/chrome/browser/ash/ownership/owner_settings_service_chromeos.h b/chrome/browser/ash/ownership/owner_settings_service_ash.h
similarity index 87%
rename from chrome/browser/ash/ownership/owner_settings_service_chromeos.h
rename to chrome/browser/ash/ownership/owner_settings_service_ash.h
index 07a4033..72878d0 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_chromeos.h
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash.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_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_H_
-#define CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_H_
+#ifndef CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_H_
+#define CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_H_
 
 #include <string>
 #include <unordered_map>
@@ -47,11 +47,10 @@
 //
 // TODO (ygorshenin@): move write path for device settings here
 // (crbug.com/230018).
-class OwnerSettingsServiceChromeOS
-    : public ownership::OwnerSettingsService,
-      public ProfileManagerObserver,
-      public chromeos::SessionManagerClient::Observer,
-      public DeviceSettingsService::Observer {
+class OwnerSettingsServiceAsh : public ownership::OwnerSettingsService,
+                                public ProfileManagerObserver,
+                                public chromeos::SessionManagerClient::Observer,
+                                public DeviceSettingsService::Observer {
  public:
   struct ManagementSettings {
     ManagementSettings();
@@ -61,9 +60,9 @@
     std::string device_id;
   };
 
-  ~OwnerSettingsServiceChromeOS() override;
+  ~OwnerSettingsServiceAsh() override;
 
-  static OwnerSettingsServiceChromeOS* FromWebUI(content::WebUI* web_ui);
+  static OwnerSettingsServiceAsh* FromWebUI(content::WebUI* web_ui);
 
   void OnTPMTokenReady(bool tpm_token_enabled);
 
@@ -115,13 +114,13 @@
       enterprise_management::ChromeDeviceSettingsProto& settings);
 
  protected:
-  OwnerSettingsServiceChromeOS(
+  OwnerSettingsServiceAsh(
       DeviceSettingsService* device_settings_service,
       Profile* profile,
       const scoped_refptr<ownership::OwnerKeyUtil>& owner_key_util);
 
  private:
-  friend class OwnerSettingsServiceChromeOSFactory;
+  friend class OwnerSettingsServiceAshFactory;
 
   // Perform fixups required to ensure sensical local-owner device policy:
   //  1) user whitelisting must be explicitly allowed or disallowed, and
@@ -191,12 +190,11 @@
   std::unique_ptr<enterprise_management::ChromeDeviceSettingsProto>
       tentative_settings_;
 
-  base::WeakPtrFactory<OwnerSettingsServiceChromeOS> weak_factory_{this};
+  base::WeakPtrFactory<OwnerSettingsServiceAsh> weak_factory_{this};
 
-  base::WeakPtrFactory<OwnerSettingsServiceChromeOS> store_settings_factory_{
-      this};
+  base::WeakPtrFactory<OwnerSettingsServiceAsh> store_settings_factory_{this};
 
-  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceChromeOS);
+  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceAsh);
 };
 
 }  // namespace ash
@@ -204,7 +202,7 @@
 // TODO(https://crbug.com/1164001): remove after //chrome/browser/chromeos
 // source migration is finished.
 namespace chromeos {
-using ::ash::OwnerSettingsServiceChromeOS;
+using ::ash::OwnerSettingsServiceAsh;
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_H_
+#endif  // CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_H_
diff --git a/chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.cc b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc
similarity index 70%
rename from chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.cc
rename to chrome/browser/ash/ownership/owner_settings_service_ash_factory.cc
index 43b87e8..7f778666 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.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/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 
 #include "base/path_service.h"
 #include "chrome/browser/ash/ownership/fake_owner_settings_service.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
@@ -34,42 +34,39 @@
 
 }  // namespace
 
-OwnerSettingsServiceChromeOSFactory::OwnerSettingsServiceChromeOSFactory()
+OwnerSettingsServiceAshFactory::OwnerSettingsServiceAshFactory()
     : BrowserContextKeyedServiceFactory(
           "OwnerSettingsService",
           BrowserContextDependencyManager::GetInstance()) {}
 
-OwnerSettingsServiceChromeOSFactory::~OwnerSettingsServiceChromeOSFactory() =
-    default;
+OwnerSettingsServiceAshFactory::~OwnerSettingsServiceAshFactory() = default;
 
 // static
-OwnerSettingsServiceChromeOS*
-OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+OwnerSettingsServiceAsh* OwnerSettingsServiceAshFactory::GetForBrowserContext(
     content::BrowserContext* context) {
-  return static_cast<OwnerSettingsServiceChromeOS*>(
+  return static_cast<OwnerSettingsServiceAsh*>(
       GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
 // static
-OwnerSettingsServiceChromeOSFactory*
-OwnerSettingsServiceChromeOSFactory::GetInstance() {
-  return base::Singleton<OwnerSettingsServiceChromeOSFactory>::get();
+OwnerSettingsServiceAshFactory* OwnerSettingsServiceAshFactory::GetInstance() {
+  return base::Singleton<OwnerSettingsServiceAshFactory>::get();
 }
 
 // static
-void OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting(
+void OwnerSettingsServiceAshFactory::SetDeviceSettingsServiceForTesting(
     DeviceSettingsService* device_settings_service) {
   g_device_settings_service_for_testing_ = device_settings_service;
 }
 
 // static
-void OwnerSettingsServiceChromeOSFactory::SetStubCrosSettingsProviderForTesting(
+void OwnerSettingsServiceAshFactory::SetStubCrosSettingsProviderForTesting(
     StubCrosSettingsProvider* stub_cros_settings_provider) {
   g_stub_cros_settings_provider_for_testing_ = stub_cros_settings_provider;
 }
 
 scoped_refptr<ownership::OwnerKeyUtil>
-OwnerSettingsServiceChromeOSFactory::GetOwnerKeyUtil() {
+OwnerSettingsServiceAshFactory::GetOwnerKeyUtil() {
   if (owner_key_util_.get())
     return owner_key_util_;
   base::FilePath public_key_path;
@@ -81,13 +78,12 @@
   return owner_key_util_;
 }
 
-void OwnerSettingsServiceChromeOSFactory::SetOwnerKeyUtilForTesting(
+void OwnerSettingsServiceAshFactory::SetOwnerKeyUtilForTesting(
     const scoped_refptr<ownership::OwnerKeyUtil>& owner_key_util) {
   owner_key_util_ = owner_key_util;
 }
 
-content::BrowserContext*
-OwnerSettingsServiceChromeOSFactory::GetBrowserContextToUse(
+content::BrowserContext* OwnerSettingsServiceAshFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
   if (profile->IsOffTheRecord() || !ProfileHelper::IsRegularProfile(profile)) {
@@ -97,12 +93,12 @@
   return context;
 }
 
-bool OwnerSettingsServiceChromeOSFactory::ServiceIsCreatedWithBrowserContext()
+bool OwnerSettingsServiceAshFactory::ServiceIsCreatedWithBrowserContext()
     const {
   return true;
 }
 
-KeyedService* OwnerSettingsServiceChromeOSFactory::BuildServiceInstanceFor(
+KeyedService* OwnerSettingsServiceAshFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   // If g_stub_cros_settings_provider_for_testing_ is set, we treat the current
   // user as the owner, and write settings directly to the stubbed provider.
@@ -114,10 +110,8 @@
         GetInstance()->GetOwnerKeyUtil());
   }
 
-  return new OwnerSettingsServiceChromeOS(
-      GetDeviceSettingsService(),
-      profile,
-      GetInstance()->GetOwnerKeyUtil());
+  return new OwnerSettingsServiceAsh(GetDeviceSettingsService(), profile,
+                                     GetInstance()->GetOwnerKeyUtil());
 }
 
 }  // namespace ash
diff --git a/chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.h
similarity index 69%
rename from chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h
rename to chrome/browser/ash/ownership/owner_settings_service_ash_factory.h
index 071e01c..7815651 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash_factory.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_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_FACTORY_H_
-#define CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_FACTORY_H_
+#ifndef CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_FACTORY_H_
+#define CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_FACTORY_H_
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
@@ -24,16 +24,16 @@
 namespace ash {
 
 class DeviceSettingsService;
-class OwnerSettingsServiceChromeOS;
+class OwnerSettingsServiceAsh;
 class StubCrosSettingsProvider;
 
-class OwnerSettingsServiceChromeOSFactory
+class OwnerSettingsServiceAshFactory
     : public BrowserContextKeyedServiceFactory {
  public:
-  static OwnerSettingsServiceChromeOS* GetForBrowserContext(
+  static OwnerSettingsServiceAsh* GetForBrowserContext(
       content::BrowserContext* context);
 
-  static OwnerSettingsServiceChromeOSFactory* GetInstance();
+  static OwnerSettingsServiceAshFactory* GetInstance();
 
   static void SetDeviceSettingsServiceForTesting(
       DeviceSettingsService* device_settings_service);
@@ -47,11 +47,10 @@
       const scoped_refptr<ownership::OwnerKeyUtil>& owner_key_util);
 
  private:
-  friend struct base::DefaultSingletonTraits<
-      OwnerSettingsServiceChromeOSFactory>;
+  friend struct base::DefaultSingletonTraits<OwnerSettingsServiceAshFactory>;
 
-  OwnerSettingsServiceChromeOSFactory();
-  ~OwnerSettingsServiceChromeOSFactory() override;
+  OwnerSettingsServiceAshFactory();
+  ~OwnerSettingsServiceAshFactory() override;
 
   // BrowserContextKeyedServiceFactory overrides:
   content::BrowserContext* GetBrowserContextToUse(
@@ -62,7 +61,7 @@
 
   scoped_refptr<ownership::OwnerKeyUtil> owner_key_util_;
 
-  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceChromeOSFactory);
+  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceAshFactory);
 };
 
 }  // namespace ash
@@ -70,7 +69,7 @@
 // TODO(https://crbug.com/1164001): remove after //chrome/browser/chromeos
 // source migration is finished.
 namespace chromeos {
-using ::ash::OwnerSettingsServiceChromeOSFactory;
+using ::ash::OwnerSettingsServiceAshFactory;
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_CHROMEOS_FACTORY_H_
+#endif  // CHROME_BROWSER_ASH_OWNERSHIP_OWNER_SETTINGS_SERVICE_ASH_FACTORY_H_
diff --git a/chrome/browser/ash/ownership/owner_settings_service_chromeos_unittest.cc b/chrome/browser/ash/ownership/owner_settings_service_ash_unittest.cc
similarity index 85%
rename from chrome/browser/ash/ownership/owner_settings_service_chromeos_unittest.cc
rename to chrome/browser/ash/ownership/owner_settings_service_ash_unittest.cc
index 3ae4786..d1bcd00 100644
--- a/chrome/browser/ash/ownership/owner_settings_service_chromeos_unittest.cc
+++ b/chrome/browser/ash/ownership/owner_settings_service_ash_unittest.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/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 
 #include <memory>
 #include <utility>
@@ -14,7 +14,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_path_override.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/device_settings_provider.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/common/chrome_paths.h"
@@ -38,7 +38,7 @@
 
 class PrefsChecker : public ownership::OwnerSettingsService::Observer {
  public:
-  PrefsChecker(OwnerSettingsServiceChromeOS* service,
+  PrefsChecker(OwnerSettingsServiceAsh* service,
                DeviceSettingsProvider* provider)
       : service_(service), provider_(provider) {
     CHECK(service_);
@@ -72,7 +72,7 @@
   void Wait() { loop_.Run(); }
 
  private:
-  OwnerSettingsServiceChromeOS* service_;
+  OwnerSettingsServiceAsh* service_;
   DeviceSettingsProvider* provider_;
   base::RunLoop loop_;
 
@@ -91,9 +91,9 @@
 
 }  // namespace
 
-class OwnerSettingsServiceChromeOSTest : public DeviceSettingsTestBase {
+class OwnerSettingsServiceAshTest : public DeviceSettingsTestBase {
  public:
-  OwnerSettingsServiceChromeOSTest()
+  OwnerSettingsServiceAshTest()
       : service_(nullptr),
         local_state_(TestingBrowserProcess::GetGlobal()),
         user_data_dir_override_(chrome::DIR_USER_DATA),
@@ -110,8 +110,8 @@
         true);
     FlushDeviceSettings();
 
-    service_ = OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
-        profile_.get());
+    service_ =
+        OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
     ASSERT_TRUE(service_);
     ASSERT_TRUE(service_->IsOwner());
 
@@ -127,7 +127,7 @@
     DeviceSettingsTestBase::TearDown();
   }
 
-  void TestSingleSet(OwnerSettingsServiceChromeOS* service,
+  void TestSingleSet(OwnerSettingsServiceAsh* service,
                      const std::string& setting,
                      const base::Value& in_value) {
     PrefsChecker checker(service, provider_.get());
@@ -147,23 +147,23 @@
   }
 
  protected:
-  OwnerSettingsServiceChromeOS* service_;
+  OwnerSettingsServiceAsh* service_;
   ScopedTestingLocalState local_state_;
   std::unique_ptr<DeviceSettingsProvider> provider_;
   base::ScopedPathOverride user_data_dir_override_;
   bool management_settings_set_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceChromeOSTest);
+  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceAshTest);
 };
 
-TEST_F(OwnerSettingsServiceChromeOSTest, SingleSetTest) {
+TEST_F(OwnerSettingsServiceAshTest, SingleSetTest) {
   TestSingleSet(service_, kReleaseChannel, base::Value("dev-channel"));
   TestSingleSet(service_, kReleaseChannel, base::Value("beta-channel"));
   TestSingleSet(service_, kReleaseChannel, base::Value("stable-channel"));
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, MultipleSetTest) {
+TEST_F(OwnerSettingsServiceAshTest, MultipleSetTest) {
   base::Value allow_guest(false);
   base::Value release_channel("stable-channel");
   base::Value show_user_names(true);
@@ -178,7 +178,7 @@
   checker.Wait();
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, FailedSetRequest) {
+TEST_F(OwnerSettingsServiceAshTest, FailedSetRequest) {
   session_manager_client_.ForceStorePolicyFailure(true);
   std::string current_channel;
   ASSERT_TRUE(provider_->Get(kReleaseChannel)->GetAsString(&current_channel));
@@ -195,7 +195,7 @@
             device_settings().release_channel().release_channel());
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, ForceAllowlist) {
+TEST_F(OwnerSettingsServiceAshTest, ForceAllowlist) {
   EXPECT_FALSE(FindInListValue(device_policy_->policy_data().username(),
                                provider_->Get(kAccountsPrefUsers)));
   // Force a settings write.
@@ -204,7 +204,7 @@
                               provider_->Get(kAccountsPrefUsers)));
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, AccountPrefUsersEmptyLists) {
+TEST_F(OwnerSettingsServiceAshTest, AccountPrefUsersEmptyLists) {
   std::vector<base::Value> list;
   list.push_back(base::Value(kUserAllowlist));
 
@@ -213,7 +213,7 @@
   EXPECT_EQ(0,
             device_policy_->payload().user_whitelist().user_whitelist().size());
 
-  OwnerSettingsServiceChromeOS::UpdateDeviceSettings(
+  OwnerSettingsServiceAsh::UpdateDeviceSettings(
       kAccountsPrefUsers, base::ListValue(list), device_policy_->payload());
 
   EXPECT_EQ(1,
@@ -224,7 +224,7 @@
             device_policy_->payload().user_whitelist().user_whitelist().size());
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, AccountPrefUsersAllowList) {
+TEST_F(OwnerSettingsServiceAshTest, AccountPrefUsersAllowList) {
   std::vector<base::Value> list;
   list.push_back(base::Value(kUserAllowlist));
 
@@ -236,7 +236,7 @@
   EXPECT_EQ(0,
             device_policy_->payload().user_whitelist().user_whitelist().size());
 
-  OwnerSettingsServiceChromeOS::UpdateDeviceSettings(
+  OwnerSettingsServiceAsh::UpdateDeviceSettings(
       kAccountsPrefUsers, base::ListValue(list), device_policy_->payload());
 
   EXPECT_EQ(1,
@@ -247,7 +247,7 @@
             device_policy_->payload().user_whitelist().user_whitelist().size());
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, AccountPrefUsersWhiteList) {
+TEST_F(OwnerSettingsServiceAshTest, AccountPrefUsersWhiteList) {
   std::vector<base::Value> list;
   list.push_back(base::Value(kUserAllowlist));
 
@@ -259,7 +259,7 @@
   EXPECT_EQ(1,
             device_policy_->payload().user_whitelist().user_whitelist().size());
 
-  OwnerSettingsServiceChromeOS::UpdateDeviceSettings(
+  OwnerSettingsServiceAsh::UpdateDeviceSettings(
       kAccountsPrefUsers, base::ListValue(list), device_policy_->payload());
 
   EXPECT_EQ(0,
@@ -270,7 +270,7 @@
             device_policy_->payload().user_whitelist().user_whitelist(0));
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, AccountPrefUsersBothLists) {
+TEST_F(OwnerSettingsServiceAshTest, AccountPrefUsersBothLists) {
   std::vector<base::Value> list;
   list.push_back(base::Value(kUserAllowlist));
 
@@ -284,7 +284,7 @@
   EXPECT_EQ(1,
             device_policy_->payload().user_whitelist().user_whitelist().size());
 
-  OwnerSettingsServiceChromeOS::UpdateDeviceSettings(
+  OwnerSettingsServiceAsh::UpdateDeviceSettings(
       kAccountsPrefUsers, base::ListValue(list), device_policy_->payload());
 
   EXPECT_EQ(1,
@@ -295,7 +295,7 @@
             device_policy_->payload().user_whitelist().user_whitelist().size());
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, MigrateFeatureFlagsAbsent) {
+TEST_F(OwnerSettingsServiceAshTest, MigrateFeatureFlagsAbsent) {
   base::HistogramTester histogram_tester;
   EXPECT_FALSE(device_settings().has_feature_flags());
 
@@ -308,7 +308,7 @@
       FeatureFlagsMigrationStatus::kNoFeatureFlags, 1);
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, MigrateFeatureFlagsNoSwitches) {
+TEST_F(OwnerSettingsServiceAshTest, MigrateFeatureFlagsNoSwitches) {
   base::HistogramTester histogram_tester;
   device_policy_->payload().mutable_feature_flags();
   EXPECT_TRUE(device_policy_->payload().has_feature_flags());
@@ -322,7 +322,7 @@
       FeatureFlagsMigrationStatus::kNoFeatureFlags, 1);
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, MigrateFeatureFlagsSuccess) {
+TEST_F(OwnerSettingsServiceAshTest, MigrateFeatureFlagsSuccess) {
   base::HistogramTester histogram_tester;
   device_policy_->payload().mutable_feature_flags()->add_switches("--foobar");
   device_policy_->Build();
@@ -347,7 +347,7 @@
       FeatureFlagsMigrationStatus::kMigrationPerformed, 1);
 }
 
-TEST_F(OwnerSettingsServiceChromeOSTest, MigrateFeatureFlagsAlreadyMigrated) {
+TEST_F(OwnerSettingsServiceAshTest, MigrateFeatureFlagsAlreadyMigrated) {
   base::HistogramTester histogram_tester;
   device_policy_->payload().mutable_feature_flags()->add_switches("--foobar");
   device_policy_->payload().mutable_feature_flags()->add_feature_flags(
@@ -374,11 +374,11 @@
       FeatureFlagsMigrationStatus::kAlreadyMigrated, 1);
 }
 
-class OwnerSettingsServiceChromeOSNoOwnerTest
-    : public OwnerSettingsServiceChromeOSTest {
+class OwnerSettingsServiceAshNoOwnerTest
+    : public OwnerSettingsServiceAshTest {
  public:
-  OwnerSettingsServiceChromeOSNoOwnerTest() {}
-  ~OwnerSettingsServiceChromeOSNoOwnerTest() override {}
+  OwnerSettingsServiceAshNoOwnerTest() {}
+  ~OwnerSettingsServiceAshNoOwnerTest() override {}
 
   void SetUp() override {
     DeviceSettingsTestBase::SetUp();
@@ -386,21 +386,21 @@
         base::BindRepeating(&OnPrefChanged), device_settings_service_.get(),
         TestingBrowserProcess::GetGlobal()->local_state()));
     FlushDeviceSettings();
-    service_ = OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
-        profile_.get());
+    service_ =
+        OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
     ASSERT_TRUE(service_);
     ASSERT_FALSE(service_->IsOwner());
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceChromeOSNoOwnerTest);
+  DISALLOW_COPY_AND_ASSIGN(OwnerSettingsServiceAshNoOwnerTest);
 };
 
-TEST_F(OwnerSettingsServiceChromeOSNoOwnerTest, SingleSetTest) {
+TEST_F(OwnerSettingsServiceAshNoOwnerTest, SingleSetTest) {
   ASSERT_FALSE(service_->SetBoolean(kAccountsPrefAllowGuest, false));
 }
 
-TEST_F(OwnerSettingsServiceChromeOSNoOwnerTest, TakeOwnershipForceAllowlist) {
+TEST_F(OwnerSettingsServiceAshNoOwnerTest, TakeOwnershipForceAllowlist) {
   EXPECT_FALSE(FindInListValue(device_policy_->policy_data().username(),
                                provider_->Get(kAccountsPrefUsers)));
   owner_key_util_->SetPrivateKey(device_policy_->GetSigningKey());
diff --git a/chrome/browser/ash/settings/cros_settings_unittest.cc b/chrome/browser/ash/settings/cros_settings_unittest.cc
index 7acdf63a..1bca17c 100644
--- a/chrome/browser/ash/settings/cros_settings_unittest.cc
+++ b/chrome/browser/ash/settings/cros_settings_unittest.cc
@@ -15,8 +15,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -65,8 +65,8 @@
     owner_key_util_->SetPublicKeyFromPrivateKey(
         *device_policy_.GetSigningKey());
     owner_key_util_->SetPrivateKey(device_policy_.GetSigningKey());
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
     DeviceSettingsService::Get()->SetSessionManager(
         &fake_session_manager_client_, owner_key_util_);
     DeviceSettingsService::Get()->Load();
@@ -81,17 +81,16 @@
   // partway through the test - this sets one up for those tests that need it.
   // Other tests below cannot use an OwnerSettingsService, since they change
   // |device_policy_| to something that would not be allowed by
-  // OwnerSettingsServiceChromeOS::FixupLocalOwnerPolicy.
-  OwnerSettingsServiceChromeOS* CreateOwnerSettingsService(
+  // OwnerSettingsServiceAsh::FixupLocalOwnerPolicy.
+  OwnerSettingsServiceAsh* CreateOwnerSettingsService(
       const std::string& owner_email) {
     const AccountId account_id = AccountId::FromUserEmail(owner_email);
     user_manager_.AddUser(account_id);
     profile_ = std::make_unique<TestingProfile>();
     profile_->set_profile_name(account_id.GetUserEmail());
 
-    OwnerSettingsServiceChromeOS* service =
-        OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
-            profile_.get());
+    OwnerSettingsServiceAsh* service =
+        OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
     DCHECK(service);
 
     service->OnTPMTokenReady(true);
@@ -233,7 +232,7 @@
 // level, the CrosSettings API.
 // They do not use OwnerSettingsService since having a local
 // OwnerSettingsService constrains the policies in certain ways - see
-// OwnerSettingsServiceChromeOS::FixupLocalOwnerPolicy.
+// OwnerSettingsServiceAsh::FixupLocalOwnerPolicy.
 
 TEST_F(CrosSettingsTest, SetEmptyAllowlist) {
   // Set an empty allowlist.
diff --git a/chrome/browser/ash/settings/device_settings_provider.cc b/chrome/browser/ash/settings/device_settings_provider.cc
index c9d1c0b..121ffe2 100644
--- a/chrome/browser/ash/settings/device_settings_provider.cc
+++ b/chrome/browser/ash/settings/device_settings_provider.cc
@@ -23,7 +23,7 @@
 #include "base/syslog_logging.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_cache.h"
 #include "chrome/browser/ash/settings/stats_reporting_controller.h"
@@ -1179,8 +1179,8 @@
     // Temporary store new setting in
     // |device_settings_|. |device_settings_| will be stored on a disk
     // as soon as an ownership of device the will be taken.
-    OwnerSettingsServiceChromeOS::UpdateDeviceSettings(path, in_value,
-                                                       device_settings_);
+    OwnerSettingsServiceAsh::UpdateDeviceSettings(path, in_value,
+                                                  device_settings_);
     em::PolicyData data;
     data.set_username(device_settings_service_->GetUsername());
     CHECK(device_settings_.SerializeToString(data.mutable_policy_value()));
diff --git a/chrome/browser/ash/settings/device_settings_provider.h b/chrome/browser/ash/settings/device_settings_provider.h
index 3436b2a..4fc704c 100644
--- a/chrome/browser/ash/settings/device_settings_provider.h
+++ b/chrome/browser/ash/settings/device_settings_provider.h
@@ -36,7 +36,7 @@
 // is in use.
 //
 // Note that the write path is in the process of being migrated to
-// OwnerSettingsServiceChromeOS (crbug.com/230018).
+// OwnerSettingsServiceAsh (crbug.com/230018).
 class DeviceSettingsProvider
     : public CrosSettingsProvider,
       public DeviceSettingsService::Observer,
diff --git a/chrome/browser/ash/settings/device_settings_service.h b/chrome/browser/ash/settings/device_settings_service.h
index d99c8ea..05bd5c21 100644
--- a/chrome/browser/ash/settings/device_settings_service.h
+++ b/chrome/browser/ash/settings/device_settings_service.h
@@ -187,7 +187,7 @@
   // TODO (ygorshenin@, crbug.com/433840): get rid of the method when
   // write path for device settings will be removed from
   // DeviceSettingsProvider and all existing clients will be switched
-  // to OwnerSettingsServiceChromeOS.
+  // to OwnerSettingsServiceAsh.
   void InitOwner(const std::string& username,
                  const base::WeakPtr<ownership::OwnerSettingsService>&
                      owner_settings_service);
@@ -212,7 +212,7 @@
   void PropertyChangeComplete(bool success) override;
 
  private:
-  friend class OwnerSettingsServiceChromeOS;
+  friend class OwnerSettingsServiceAsh;
 
   // Enqueues a new operation. Takes ownership of |operation| and starts it
   // right away if there is no active operation currently.
diff --git a/chrome/browser/ash/settings/device_settings_service_unittest.cc b/chrome/browser/ash/settings/device_settings_service_unittest.cc
index a254327..620deda 100644
--- a/chrome/browser/ash/settings/device_settings_service_unittest.cc
+++ b/chrome/browser/ash/settings/device_settings_service_unittest.cc
@@ -12,8 +12,8 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
@@ -269,8 +269,8 @@
 
   const std::string& user_id = device_policy_->policy_data().username();
   InitOwner(AccountId::FromUserEmail(user_id), false);
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   ASSERT_TRUE(service);
   service->IsOwnerAsync(base::BindOnce(&DeviceSettingsServiceTest::OnIsOwner,
                                        base::Unretained(this)));
@@ -313,8 +313,8 @@
   const std::string& user_id = device_policy_->policy_data().username();
   owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_->GetSigningKey());
   InitOwner(AccountId::FromUserEmail(user_id), false);
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   ASSERT_TRUE(service);
   ReloadDeviceSettings();
 
@@ -348,8 +348,8 @@
   const std::string& user_id = device_policy_->policy_data().username();
   owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_->GetSigningKey());
   InitOwner(AccountId::FromUserEmail(user_id), false);
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   ASSERT_TRUE(service);
   service->IsOwnerAsync(base::BindOnce(&DeviceSettingsServiceTest::OnIsOwner,
                                        base::Unretained(this)));
@@ -404,8 +404,8 @@
             device_settings_service_->GetOwnershipStatus());
   EXPECT_FALSE(is_owner_set_);
 
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   ASSERT_TRUE(service);
   service->IsOwnerAsync(base::BindOnce(&DeviceSettingsServiceTest::OnIsOwner,
                                        base::Unretained(this)));
@@ -475,8 +475,8 @@
   const std::string& user_id = device_policy_->policy_data().username();
   owner_key_util_->SetPublicKeyFromPrivateKey(*device_policy_->GetSigningKey());
   InitOwner(AccountId::FromUserEmail(user_id), false);
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   ASSERT_TRUE(service);
   service->IsOwnerAsync(base::BindOnce(&DeviceSettingsServiceTest::OnIsOwner,
                                        base::Unretained(this)));
diff --git a/chrome/browser/ash/settings/device_settings_test_helper.cc b/chrome/browser/ash/settings/device_settings_test_helper.cc
index 7d512bb..f3b796c 100644
--- a/chrome/browser/ash/settings/device_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/device_settings_test_helper.cc
@@ -6,8 +6,8 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/test/base/testing_profile.h"
@@ -59,9 +59,9 @@
   chromeos::CryptohomeClient::InitializeFake();
   PowerManagerClient::InitializeFake();
   chromeos::TpmManagerClient::InitializeFake();
-  OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting(
+  OwnerSettingsServiceAshFactory::SetDeviceSettingsServiceForTesting(
       device_settings_service_.get());
-  OwnerSettingsServiceChromeOSFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+  OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
       owner_key_util_);
   base::RunLoop().RunUntilIdle();
 
@@ -77,8 +77,7 @@
 
 void DeviceSettingsTestBase::TearDown() {
   teardown_called_ = true;
-  OwnerSettingsServiceChromeOSFactory::SetDeviceSettingsServiceForTesting(
-      nullptr);
+  OwnerSettingsServiceAshFactory::SetDeviceSettingsServiceForTesting(nullptr);
   FlushDeviceSettings();
   device_settings_service_->UnsetSessionManager();
   device_settings_service_.reset();
@@ -117,8 +116,8 @@
     ProfileHelper::Get()->SetProfileToUserMappingForTesting(
         const_cast<user_manager::User*>(user));
   }
-  OwnerSettingsServiceChromeOS* service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_.get());
+  OwnerSettingsServiceAsh* service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   CHECK(service);
   if (tpm_is_ready)
     service->OnTPMTokenReady(true /* token is enabled */);
diff --git a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
index a91a1e3e..25b592e2 100644
--- a/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
+++ b/chrome/browser/ash/settings/scoped_cros_settings_test_helper.cc
@@ -8,7 +8,7 @@
 #include "base/check.h"
 #include "base/values.h"
 #include "chrome/browser/ash/ownership/fake_owner_settings_service.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_cache.h"
 #include "chrome/browser/ash/settings/device_settings_provider.h"
@@ -120,7 +120,7 @@
                                         g_browser_process->local_state())) {
       CHECK(settings.ParseFromString(data.policy_value()));
     }
-    OwnerSettingsServiceChromeOS::UpdateDeviceSettings(path, *value, settings);
+    OwnerSettingsServiceAsh::UpdateDeviceSettings(path, *value, settings);
     CHECK(settings.SerializeToString(data.mutable_policy_value()));
     CHECK(device_settings_cache::Store(data, g_browser_process->local_state()));
     g_browser_process->local_state()->CommitPendingWrite(base::DoNothing(),
diff --git a/chrome/browser/ash/settings/scoped_testing_cros_settings.cc b/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
index fe969cf..42f57ef 100644
--- a/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
+++ b/chrome/browser/ash/settings/scoped_testing_cros_settings.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chromeos/settings/system_settings_provider.h"
@@ -16,7 +16,7 @@
 
   std::unique_ptr<StubCrosSettingsProvider> device_settings =
       std::make_unique<StubCrosSettingsProvider>();
-  OwnerSettingsServiceChromeOSFactory::SetStubCrosSettingsProviderForTesting(
+  OwnerSettingsServiceAshFactory::SetStubCrosSettingsProviderForTesting(
       device_settings.get());
   device_settings_ptr_ = device_settings.get();
   test_instance_->AddSettingsProvider(std::move(device_settings));
@@ -30,7 +30,7 @@
 }
 
 ScopedTestingCrosSettings::~ScopedTestingCrosSettings() {
-  OwnerSettingsServiceChromeOSFactory::SetStubCrosSettingsProviderForTesting(
+  OwnerSettingsServiceAshFactory::SetStubCrosSettingsProviderForTesting(
       nullptr);
   device_settings_ptr_ = nullptr;
   system_settings_ptr_ = nullptr;
diff --git a/chrome/browser/ash/settings/scoped_testing_cros_settings.h b/chrome/browser/ash/settings/scoped_testing_cros_settings.h
index ad8225c..6b25acdd 100644
--- a/chrome/browser/ash/settings/scoped_testing_cros_settings.h
+++ b/chrome/browser/ash/settings/scoped_testing_cros_settings.h
@@ -24,7 +24,7 @@
 // a StubCrosSettingsProvider for device settings,
 // and a regular SystemSettingsProvider for the system settings.
 //
-// OwnerSettingsServiceChromeOSFactory::SetStubCrosSettingsProviderForTesting is
+// OwnerSettingsServiceAshFactory::SetStubCrosSettingsProviderForTesting is
 // caled too, with the StubCrosSettingsProvider, so that any
 // OwnerSettingsService created will write to the StubCrosSettingsProvider.
 //
diff --git a/chrome/browser/ash/settings/session_manager_operation_unittest.cc b/chrome/browser/ash/settings/session_manager_operation_unittest.cc
index 32888ec..8addfd4 100644
--- a/chrome/browser/ash/settings/session_manager_operation_unittest.cc
+++ b/chrome/browser/ash/settings/session_manager_operation_unittest.cc
@@ -17,8 +17,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/ownership/mock_owner_key_util.h"
@@ -73,8 +73,8 @@
         user_manager_(new chromeos::FakeChromeUserManager()),
         user_manager_enabler_(base::WrapUnique(user_manager_)),
         validated_(false) {
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        owner_key_util_);
   }
 
   void SetUp() override {
@@ -83,8 +83,8 @@
     policy_.Build();
 
     profile_.reset(new TestingProfile());
-    service_ = OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
-        profile_.get());
+    service_ =
+        OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_.get());
   }
 
   MOCK_METHOD2(OnOperationCompleted,
@@ -118,7 +118,7 @@
   user_manager::ScopedUserManager user_manager_enabler_;
 
   std::unique_ptr<TestingProfile> profile_;
-  OwnerSettingsServiceChromeOS* service_;
+  OwnerSettingsServiceAsh* service_;
 
   bool validated_;
 
diff --git a/chrome/browser/ash/settings/stats_reporting_controller.cc b/chrome/browser/ash/settings/stats_reporting_controller.cc
index 20830712..46336bd 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller.cc
+++ b/chrome/browser/ash/settings/stats_reporting_controller.cc
@@ -8,8 +8,8 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -220,7 +220,7 @@
 
 ownership::OwnerSettingsService*
 StatsReportingController::GetOwnerSettingsService(Profile* profile) {
-  return OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile);
+  return OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
 }
 
 bool StatsReportingController::GetPendingValue(bool* result) {
diff --git a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
index 15537be..91d1d40 100644
--- a/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
+++ b/chrome/browser/ash/settings/stats_reporting_controller_unittest.cc
@@ -10,8 +10,8 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/device_settings_cache.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -57,10 +57,10 @@
 
   std::unique_ptr<TestingProfile> CreateUser(
       scoped_refptr<ownership::MockOwnerKeyUtil> keys) {
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(keys);
+    OwnerSettingsServiceAshFactory::GetInstance()->SetOwnerKeyUtilForTesting(
+        keys);
     std::unique_ptr<TestingProfile> user = std::make_unique<TestingProfile>();
-    OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(user.get())
+    OwnerSettingsServiceAshFactory::GetForBrowserContext(user.get())
         ->OnTPMTokenReady(true);
     content::RunAllTasksUntilIdle();
     return user;
@@ -243,7 +243,7 @@
 
   // After device is owned, the value is written to Cros settings.
   StatsReportingController::Get()->OnOwnershipTaken(
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(owner.get()));
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(owner.get()));
   EXPECT_TRUE(StatsReportingController::Get()->IsEnabled());
   EXPECT_TRUE(value_at_last_notification_);
   ExpectThatPendingValueIs(true);
diff --git a/chrome/browser/ash/system/system_clock.cc b/chrome/browser/ash/system/system_clock.cc
index f924b204..789bd99 100644
--- a/chrome/browser/ash/system/system_clock.cc
+++ b/chrome/browser/ash/system/system_clock.cc
@@ -8,8 +8,8 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/system/system_clock_observer.h"
@@ -36,8 +36,8 @@
   Profile* const profile = ProfileHelper::Get()->GetProfileByUser(user);
   if (!profile)
     return;  // May occur in tests or if not running on a device.
-  OwnerSettingsServiceChromeOS* const service =
-      OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile);
+  OwnerSettingsServiceAsh* const service =
+      OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
   CHECK(service);
   service->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
 }
diff --git a/chrome/browser/ash/web_applications/personalization_app_info.cc b/chrome/browser/ash/web_applications/personalization_app_info.cc
new file mode 100644
index 0000000..70a4cc90
--- /dev/null
+++ b/chrome/browser/ash/web_applications/personalization_app_info.cc
@@ -0,0 +1,32 @@
+// 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/ash/web_applications/personalization_app_info.h"
+
+#include <memory>
+
+#include "chrome/browser/ash/web_applications/system_web_app_install_utils.h"
+#include "chrome/browser/web_applications/components/web_application_info.h"
+#include "chromeos/components/personalization_app/personalization_app_url_constants.h"
+#include "chromeos/grit/chromeos_personalization_app_resources.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "third_party/blink/public/mojom/manifest/display_mode.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
+
+std::unique_ptr<WebApplicationInfo> CreateWebAppInfoForPersonalizationApp() {
+  std::unique_ptr<WebApplicationInfo> info =
+      std::make_unique<WebApplicationInfo>();
+  info->start_url = GURL(chromeos::kChromeUIPersonalizationAppURL);
+  info->scope = GURL(chromeos::kChromeUIPersonalizationAppURL);
+  info->title = l10n_util::GetStringUTF16(IDS_PERSONALIZATION_APP_TITLE);
+  web_app::CreateIconInfoForSystemWebApp(
+      info->start_url,
+      {{"app_icon_192.png", 192,
+        IDR_CHROMEOS_PERSONALIZATION_APP_ICON_192_PNG}},
+      *info);
+  info->display_mode = blink::mojom::DisplayMode::kStandalone;
+  info->open_as_window = true;
+
+  return info;
+}
diff --git a/chrome/browser/ash/web_applications/personalization_app_info.h b/chrome/browser/ash/web_applications/personalization_app_info.h
new file mode 100644
index 0000000..323391c
--- /dev/null
+++ b/chrome/browser/ash/web_applications/personalization_app_info.h
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_
+#define CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_
+
+#include <memory>
+
+struct WebApplicationInfo;
+
+// Return a WebApplicationInfo used to install the app.
+std::unique_ptr<WebApplicationInfo> CreateWebAppInfoForPersonalizationApp();
+
+#endif  // CHROME_BROWSER_ASH_WEB_APPLICATIONS_PERSONALIZATION_APP_INFO_H_
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index ddacb7e..4a5acae2 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -101,8 +101,8 @@
   scoped_refptr<Extension> extension;
 
   extension = Extension::Create(bogus_file_pathname(name),
-                                extensions::Manifest::INTERNAL, manifest,
-                                Extension::NO_FLAGS, &error);
+                                extensions::mojom::ManifestLocation::kInternal,
+                                manifest, Extension::NO_FLAGS, &error);
 
   // Cannot ASSERT_* here because that attempts an illegitimate return.
   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
diff --git a/chrome/browser/bad_message.cc b/chrome/browser/bad_message.cc
index 1d57bad4..dc9cbbe3 100644
--- a/chrome/browser/bad_message.cc
+++ b/chrome/browser/bad_message.cc
@@ -14,8 +14,6 @@
 namespace {
 
 void LogBadMessage(BadMessageReason reason) {
-  TRACE_EVENT_INSTANT1("ipc,security", "chrome::ReceivedBadMessage",
-                       TRACE_EVENT_SCOPE_THREAD, "reason", reason);
   LOG(ERROR) << "Terminating renderer for bad IPC message, reason " << reason;
   base::UmaHistogramSparse("Stability.BadMessageTerminated.Chrome", reason);
 }
@@ -24,6 +22,9 @@
 
 void ReceivedBadMessage(content::RenderProcessHost* host,
                         BadMessageReason reason) {
+  TRACE_EVENT_INSTANT2("ipc,security", "chrome::ReceivedBadMessage",
+                       TRACE_EVENT_SCOPE_THREAD, "reason", reason,
+                       "render_process_host", host);
   LogBadMessage(reason);
   host->ShutdownForBadMessage(
       content::RenderProcessHost::CrashReportMode::GENERATE_CRASH_DUMP);
@@ -31,6 +32,8 @@
 
 void ReceivedBadMessage(content::BrowserMessageFilter* filter,
                         BadMessageReason reason) {
+  TRACE_EVENT_INSTANT1("ipc,security", "chrome::ReceivedBadMessage",
+                       TRACE_EVENT_SCOPE_THREAD, "reason", reason);
   LogBadMessage(reason);
   filter->ShutdownForBadMessage();
 }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 7aaf5cf..b985cbc 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -309,6 +309,7 @@
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/site_isolation_policy.h"
+#include "content/public/browser/sms_fetcher.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/tts_controller.h"
 #include "content/public/browser/tts_platform.h"
@@ -5648,7 +5649,9 @@
     content::BrowserContext* browser_context,
     const url::Origin& origin,
     base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
-                            base::Optional<std::string>)> callback) {
+                            base::Optional<std::string>,
+                            base::Optional<content::SmsFetchFailureType>)>
+        callback) {
   ::FetchRemoteSms(browser_context, origin, std::move(callback));
 }
 #endif
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index ec8c8de..8c07fab 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -56,6 +56,7 @@
 class BrowserContext;
 class FontAccessDelegate;
 class QuotaPermissionContext;
+enum class SmsFetchFailureType;
 }  // namespace content
 
 namespace safe_browsing {
@@ -652,7 +653,9 @@
       content::BrowserContext* browser_context,
       const url::Origin& origin,
       base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
-                              base::Optional<std::string>)> callback) override;
+                              base::Optional<std::string>,
+                              base::Optional<content::SmsFetchFailureType>)>
+          callback) override;
 #endif
 
   bool IsClipboardPasteAllowed(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index ef02fc1..bf9e6635 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -134,6 +134,7 @@
     "//chromeos/components/multidevice",
     "//chromeos/components/multidevice:stub_multidevice_util",
     "//chromeos/components/multidevice/logging",
+    "//chromeos/components/personalization_app",
     "//chromeos/components/phonehub",
     "//chromeos/components/power",
     "//chromeos/components/print_management",
@@ -219,6 +220,7 @@
     "//chromeos/resources:eche_bundle_resources_grit",
     "//chromeos/resources:help_app_resources_grit",
     "//chromeos/resources:media_app_resources_grit",
+    "//chromeos/resources:personalization_app_resources_grit",
     "//chromeos/resources:print_management_resources_grit",
     "//chromeos/resources:scanning_app_resources_grit",
     "//chromeos/services/assistant/public/cpp",
@@ -567,6 +569,45 @@
     "../ash/apps/intent_helper/common_apps_navigation_throttle.h",
     "../ash/apps/metrics/intent_handling_metrics.cc",
     "../ash/apps/metrics/intent_handling_metrics.h",
+    "../ash/arc/accessibility/accessibility_info_data_wrapper.cc",
+    "../ash/arc/accessibility/accessibility_info_data_wrapper.h",
+    "../ash/arc/accessibility/accessibility_node_info_data_wrapper.cc",
+    "../ash/arc/accessibility/accessibility_node_info_data_wrapper.h",
+    "../ash/arc/accessibility/accessibility_window_info_data_wrapper.cc",
+    "../ash/arc/accessibility/accessibility_window_info_data_wrapper.h",
+    "../ash/arc/accessibility/arc_accessibility_helper_bridge.cc",
+    "../ash/arc/accessibility/arc_accessibility_helper_bridge.h",
+    "../ash/arc/accessibility/arc_accessibility_util.cc",
+    "../ash/arc/accessibility/arc_accessibility_util.h",
+    "../ash/arc/accessibility/auto_complete_handler.cc",
+    "../ash/arc/accessibility/auto_complete_handler.h",
+    "../ash/arc/accessibility/ax_tree_source_arc.cc",
+    "../ash/arc/accessibility/ax_tree_source_arc.h",
+    "../ash/arc/accessibility/drawer_layout_handler.cc",
+    "../ash/arc/accessibility/drawer_layout_handler.h",
+    "../ash/arc/accessibility/geometry_util.cc",
+    "../ash/arc/accessibility/geometry_util.h",
+    "../ash/arc/adbd/arc_adbd_monitor_bridge.cc",
+    "../ash/arc/adbd/arc_adbd_monitor_bridge.h",
+    "../ash/arc/app_shortcuts/arc_app_shortcut_item.cc",
+    "../ash/arc/app_shortcuts/arc_app_shortcut_item.h",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_request.cc",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_request.h",
+    "../ash/arc/auth/arc_active_directory_enrollment_token_fetcher.cc",
+    "../ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h",
+    "../ash/arc/auth/arc_auth_code_fetcher.h",
+    "../ash/arc/auth/arc_auth_context.cc",
+    "../ash/arc/auth/arc_auth_context.h",
+    "../ash/arc/auth/arc_auth_service.cc",
+    "../ash/arc/auth/arc_auth_service.h",
+    "../ash/arc/auth/arc_background_auth_code_fetcher.cc",
+    "../ash/arc/auth/arc_background_auth_code_fetcher.h",
+    "../ash/arc/auth/arc_fetcher_base.cc",
+    "../ash/arc/auth/arc_fetcher_base.h",
+    "../ash/arc/auth/arc_robot_auth_code_fetcher.cc",
+    "../ash/arc/auth/arc_robot_auth_code_fetcher.h",
     "../ash/assistant/assistant_util.cc",
     "../ash/assistant/assistant_util.h",
     "../ash/attestation/attestation_ca_client.cc",
@@ -1130,10 +1171,10 @@
     "../ash/notifications/deprecation_notification_controller.h",
     "../ash/ownership/fake_owner_settings_service.cc",
     "../ash/ownership/fake_owner_settings_service.h",
-    "../ash/ownership/owner_settings_service_chromeos.cc",
-    "../ash/ownership/owner_settings_service_chromeos.h",
-    "../ash/ownership/owner_settings_service_chromeos_factory.cc",
-    "../ash/ownership/owner_settings_service_chromeos_factory.h",
+    "../ash/ownership/owner_settings_service_ash.cc",
+    "../ash/ownership/owner_settings_service_ash.h",
+    "../ash/ownership/owner_settings_service_ash_factory.cc",
+    "../ash/ownership/owner_settings_service_ash_factory.h",
     "../ash/plugin_vm/plugin_vm_drive_image_download_service.cc",
     "../ash/plugin_vm/plugin_vm_drive_image_download_service.h",
     "../ash/plugin_vm/plugin_vm_engagement_metrics_service.cc",
@@ -1292,6 +1333,8 @@
     "../ash/web_applications/media_web_app_info.h",
     "../ash/web_applications/os_settings_web_app_info.cc",
     "../ash/web_applications/os_settings_web_app_info.h",
+    "../ash/web_applications/personalization_app_info.cc",
+    "../ash/web_applications/personalization_app_info.h",
     "../ash/web_applications/print_management_web_app_info.cc",
     "../ash/web_applications/print_management_web_app_info.h",
     "../ash/web_applications/scanning_system_web_app_info.cc",
@@ -1328,32 +1371,6 @@
     "android_sms/fcm_connection_establisher.h",
     "android_sms/pairing_lost_notifier.cc",
     "android_sms/pairing_lost_notifier.h",
-    "arc/accessibility/accessibility_info_data_wrapper.cc",
-    "arc/accessibility/accessibility_info_data_wrapper.h",
-    "arc/accessibility/accessibility_node_info_data_wrapper.cc",
-    "arc/accessibility/accessibility_node_info_data_wrapper.h",
-    "arc/accessibility/accessibility_window_info_data_wrapper.cc",
-    "arc/accessibility/accessibility_window_info_data_wrapper.h",
-    "arc/accessibility/arc_accessibility_helper_bridge.cc",
-    "arc/accessibility/arc_accessibility_helper_bridge.h",
-    "arc/accessibility/arc_accessibility_util.cc",
-    "arc/accessibility/arc_accessibility_util.h",
-    "arc/accessibility/auto_complete_handler.cc",
-    "arc/accessibility/auto_complete_handler.h",
-    "arc/accessibility/ax_tree_source_arc.cc",
-    "arc/accessibility/ax_tree_source_arc.h",
-    "arc/accessibility/drawer_layout_handler.cc",
-    "arc/accessibility/drawer_layout_handler.h",
-    "arc/accessibility/geometry_util.cc",
-    "arc/accessibility/geometry_util.h",
-    "arc/adbd/arc_adbd_monitor_bridge.cc",
-    "arc/adbd/arc_adbd_monitor_bridge.h",
-    "arc/app_shortcuts/arc_app_shortcut_item.cc",
-    "arc/app_shortcuts/arc_app_shortcut_item.h",
-    "arc/app_shortcuts/arc_app_shortcuts_menu_builder.cc",
-    "arc/app_shortcuts/arc_app_shortcuts_menu_builder.h",
-    "arc/app_shortcuts/arc_app_shortcuts_request.cc",
-    "arc/app_shortcuts/arc_app_shortcuts_request.h",
     "arc/arc_demo_mode_delegate_impl.cc",
     "arc/arc_demo_mode_delegate_impl.h",
     "arc/arc_migration_constants.h",
@@ -1369,19 +1386,6 @@
     "arc/arc_util.h",
     "arc/arc_web_contents_data.cc",
     "arc/arc_web_contents_data.h",
-    "arc/auth/arc_active_directory_enrollment_token_fetcher.cc",
-    "arc/auth/arc_active_directory_enrollment_token_fetcher.h",
-    "arc/auth/arc_auth_code_fetcher.h",
-    "arc/auth/arc_auth_context.cc",
-    "arc/auth/arc_auth_context.h",
-    "arc/auth/arc_auth_service.cc",
-    "arc/auth/arc_auth_service.h",
-    "arc/auth/arc_background_auth_code_fetcher.cc",
-    "arc/auth/arc_background_auth_code_fetcher.h",
-    "arc/auth/arc_fetcher_base.cc",
-    "arc/auth/arc_fetcher_base.h",
-    "arc/auth/arc_robot_auth_code_fetcher.cc",
-    "arc/auth/arc_robot_auth_code_fetcher.h",
     "arc/bluetooth/arc_bluetooth_bridge.cc",
     "arc/bluetooth/arc_bluetooth_bridge.h",
     "arc/bluetooth/arc_bluetooth_task_queue.cc",
@@ -3491,6 +3495,16 @@
     "../ash/app_mode/web_app/web_kiosk_app_launcher_unittest.cc",
     "../ash/apps/apk_web_app_installer_unittest.cc",
     "../ash/apps/metrics/intent_handling_metrics_unittest.cc",
+    "../ash/arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc",
+    "../ash/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc",
+    "../ash/arc/accessibility/arc_accessibility_test_util.h",
+    "../ash/arc/accessibility/arc_accessibility_util_unittest.cc",
+    "../ash/arc/accessibility/auto_complete_handler_unittest.cc",
+    "../ash/arc/accessibility/ax_tree_source_arc_unittest.cc",
+    "../ash/arc/accessibility/drawer_layout_handler_unittest.cc",
+    "../ash/arc/adbd/arc_adbd_monitor_bridge_unittest.cc",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc",
+    "../ash/arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc",
     "../ash/assistant/assistant_util_unittest.cc",
     "../ash/attestation/attestation_ca_client_unittest.cc",
     "../ash/attestation/attestation_policy_observer_unittest.cc",
@@ -3581,7 +3595,7 @@
     "../ash/login/version_updater/version_updater_unittest.cc",
     "../ash/mobile/mobile_activator_unittest.cc",
     "../ash/notifications/deprecation_notification_controller_unittest.cc",
-    "../ash/ownership/owner_settings_service_chromeos_unittest.cc",
+    "../ash/ownership/owner_settings_service_ash_unittest.cc",
     "../ash/plugin_vm/mock_plugin_vm_manager.cc",
     "../ash/plugin_vm/mock_plugin_vm_manager.h",
     "../ash/plugin_vm/plugin_vm_features_unittest.cc",
@@ -3633,16 +3647,6 @@
     "android_sms/connection_manager_unittest.cc",
     "android_sms/fcm_connection_establisher_unittest.cc",
     "android_sms/pairing_lost_notifier_unittest.cc",
-    "arc/accessibility/accessibility_node_info_data_wrapper_unittest.cc",
-    "arc/accessibility/arc_accessibility_helper_bridge_unittest.cc",
-    "arc/accessibility/arc_accessibility_test_util.h",
-    "arc/accessibility/arc_accessibility_util_unittest.cc",
-    "arc/accessibility/auto_complete_handler_unittest.cc",
-    "arc/accessibility/ax_tree_source_arc_unittest.cc",
-    "arc/accessibility/drawer_layout_handler_unittest.cc",
-    "arc/adbd/arc_adbd_monitor_bridge_unittest.cc",
-    "arc/app_shortcuts/arc_app_shortcuts_menu_builder_unittest.cc",
-    "arc/app_shortcuts/arc_app_shortcuts_request_unittest.cc",
     "arc/arc_demo_mode_delegate_impl_unittest.cc",
     "arc/arc_migration_guide_notification_unittest.cc",
     "arc/arc_support_host_unittest.cc",
diff --git a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
index 5e8afab0..4b6351b 100644
--- a/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/session/arc_service_launcher.cc
@@ -13,12 +13,12 @@
 #include "base/files/file_util.h"
 #include "chrome/browser/apps/app_service/arc_apps_factory.h"
 #include "chrome/browser/ash/apps/apk_web_app_service.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
+#include "chrome/browser/ash/arc/adbd/arc_adbd_monitor_bridge.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
-#include "chrome/browser/chromeos/arc/adbd/arc_adbd_monitor_bridge.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/bluetooth/arc_bluetooth_bridge.h"
 #include "chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
 #include "chrome/browser/chromeos/arc/cast_receiver/arc_cast_receiver_service.h"
diff --git a/chrome/browser/chromeos/arc/session/arc_session_manager.cc b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
index 4d79875..2b8a8bd7 100644
--- a/chrome/browser/chromeos/arc/session/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/session/arc_session_manager.cc
@@ -22,6 +22,7 @@
 #include "base/task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
 #include "chrome/browser/ash/login/demo_mode/demo_resources.h"
 #include "chrome/browser/ash/login/demo_mode/demo_session.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
@@ -32,7 +33,6 @@
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/arc/arc_ui_availability_reporter.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/arc/auth/arc_auth_service.h"
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_default_negotiator.h"
 #include "chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.h"
 #include "chrome/browser/chromeos/arc/policy/arc_android_management_checker.h"
@@ -65,7 +65,6 @@
 #include "components/arc/session/arc_session_runner.h"
 #include "components/arc/session/arc_supervision_transition.h"
 #include "components/prefs/pref_service.h"
-#include "components/services/app_service/public/cpp/intent_util.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_thread.h"
@@ -682,10 +681,10 @@
             prefs->GetBoolean(prefs::kArcProvisioningInitiatedFromOobe))) {
       playstore_launcher_ = std::make_unique<ArcAppLauncher>(
           profile_, kPlayStoreAppId,
-          apps_util::CreateIntentForActivity(kPlayStoreActivity,
-                                             kInitialStartParam),
+          GetLaunchIntent(kPlayStorePackage, kPlayStoreActivity,
+                          {kInitialStartParam}),
           false /* deferred_launch_allowed */, display::kInvalidDisplayId,
-          apps::mojom::LaunchSource::kFromChromeInternal);
+          arc::UserInteractionType::NOT_USER_INITIATED);
     }
 
     prefs->ClearPref(prefs::kArcProvisioningInitiatedFromOobe);
diff --git a/chrome/browser/chromeos/arc/tts/OWNERS b/chrome/browser/chromeos/arc/tts/OWNERS
index 9cfcb59e..a715e784 100644
--- a/chrome/browser/chromeos/arc/tts/OWNERS
+++ b/chrome/browser/chromeos/arc/tts/OWNERS
@@ -1 +1 @@
-file://chrome/browser/chromeos/arc/accessibility/OWNERS
+file://chrome/browser/ash/arc/accessibility/OWNERS
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
index d2b95cd..df73b33 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
@@ -31,9 +31,7 @@
     : primary_user_email_(primary_user_email), pref_service_(pref_service) {
   // For Googlers, set the default preference of Bluetooth verbose logs to true.
   if (AreDebugLogsSupported() &&
-      !pref_service->HasPrefPath(kVerboseLoggingEnablePrefName) &&
-      base::FeatureList::IsEnabled(
-          chromeos::features::kEnableBluetoothVerboseLogsForGooglers)) {
+      !pref_service->HasPrefPath(kVerboseLoggingEnablePrefName)) {
     ChangeDebugLogsState(true);
   }
 
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
index 0658f7e..78b8d40 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager_unittest.cc
@@ -51,10 +51,6 @@
 
   void EnableDebugFlag() { is_debug_toggle_flag_enabled_ = true; }
 
-  void EnableGooglerDefaultPrefFlag() {
-    is_googler_default_pref_enabled_ = true;
-  }
-
   void InitFeatures() {
     std::vector<base::Feature> enabled_features;
     std::vector<base::Feature> disabled_features;
@@ -67,14 +63,6 @@
           chromeos::features::kShowBluetoothDebugLogToggle);
     }
 
-    if (is_googler_default_pref_enabled_) {
-      enabled_features.push_back(
-          chromeos::features::kEnableBluetoothVerboseLogsForGooglers);
-    } else {
-      disabled_features.push_back(
-          chromeos::features::kEnableBluetoothVerboseLogsForGooglers);
-    }
-
     feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
@@ -94,7 +82,6 @@
  private:
   base::test::ScopedFeatureList feature_list_;
   bool is_debug_toggle_flag_enabled_ = false;
-  bool is_googler_default_pref_enabled_ = false;
   bluez::FakeBluetoothDebugManagerClient* fake_bluetooth_debug_manager_client_;
   std::unique_ptr<DebugLogsManager> debug_logs_manager_;
   TestingPrefServiceSimple prefs_;
@@ -120,7 +107,6 @@
 
 TEST_F(DebugLogsManagerTest, GooglerDefaultPref) {
   EnableDebugFlag();
-  EnableGooglerDefaultPrefFlag();
   InitFeatures();
   InstantiateDebugManager(kTestGooglerEmail);
   EXPECT_EQ(debug_manager()->GetDebugLogsState(),
@@ -132,17 +118,6 @@
   InitFeatures();
   InstantiateDebugManager(kTestGooglerEmail);
   EXPECT_EQ(debug_manager()->GetDebugLogsState(),
-            DebugLogsManager::DebugLogsState::kSupportedButDisabled);
-
-  debug_manager()->ChangeDebugLogsState(
-      true /* should_debug_logs_be_enabled */);
-  EXPECT_EQ(debug_manager()->GetDebugLogsState(),
-            DebugLogsManager::DebugLogsState::kSupportedAndEnabled);
-
-  // Despite DebugLogsManager is destroyed, the state of Debug logs is saved
-  DestroyDebugManager();
-  InstantiateDebugManager(kTestGooglerEmail);
-  EXPECT_EQ(debug_manager()->GetDebugLogsState(),
             DebugLogsManager::DebugLogsState::kSupportedAndEnabled);
 
   debug_manager()->ChangeDebugLogsState(
@@ -160,15 +135,6 @@
   EnableDebugFlag();
   InitFeatures();
   InstantiateDebugManager(kTestGooglerEmail);
-  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 0);
-  debug_manager()->ChangeDebugLogsState(
-      true /* should_debug_logs_be_enabled */);
-  // BlueZ level is updated only on login/logout, so now it stays the same.
-  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 0);
-
-  // Deletion and Recreation of DebugManager simulates logout-login event
-  DestroyDebugManager();
-  InstantiateDebugManager(kTestGooglerEmail);
   // After login, bluez level should change
   EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 1);
 
@@ -198,9 +164,9 @@
   EnableDebugFlag();
   InitFeatures();
   InstantiateDebugManager(kTestGooglerEmail);
-  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 0);
+  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 1);
   debug_manager()->ChangeDebugLogsState(
-      true /* should_debug_logs_be_enabled */);
+      false /* should_debug_logs_be_enabled */);
 
   DestroyDebugManager();
   fake_bluetooth_debug_manager_client()->MakeNextSetLogLevelsFail();
@@ -210,7 +176,7 @@
   EXPECT_EQ(fake_bluetooth_debug_manager_client()->set_log_levels_fail_count(),
             1);
   // Message is re-sent upon failing, eventually bluez level should change.
-  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 1);
+  EXPECT_EQ(fake_bluetooth_debug_manager_client()->bluez_level(), 0);
 }
 
 }  // namespace bluetooth
diff --git a/chrome/browser/chromeos/browser_context_keyed_service_factories.cc b/chrome/browser/chromeos/browser_context_keyed_service_factories.cc
index 46d2efd..8032ccb 100644
--- a/chrome/browser/chromeos/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/chromeos/browser_context_keyed_service_factories.cc
@@ -5,13 +5,13 @@
 #include "chrome/browser/chromeos/browser_context_keyed_service_factories.h"
 
 #include "chrome/browser/ash/account_manager/account_manager_migrator.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 #include "chrome/browser/ash/authpolicy/authpolicy_credentials_manager.h"
 #include "chrome/browser/ash/login/easy_unlock/easy_unlock_service_factory.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_engagement_metrics_service.h"
 #include "chrome/browser/ash/web_applications/crosh_loader_factory.h"
 #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h"
 #include "chrome/browser/chromeos/cert_provisioning/cert_provisioning_scheduler_user_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_engagement_metrics_service.h"
@@ -91,7 +91,7 @@
   launcher_search_provider::ServiceFactory::GetInstance();
   nearby::NearbyConnectionsDependenciesProviderFactory::GetInstance();
   nearby::NearbyProcessManagerFactory::GetInstance();
-  OwnerSettingsServiceChromeOSFactory::GetInstance();
+  OwnerSettingsServiceAshFactory::GetInstance();
   phonehub::PhoneHubManagerFactory::GetInstance();
   platform_keys::KeyPermissionsServiceFactory::GetInstance();
   platform_keys::UserPrivateTokenKeyPermissionsManagerServiceFactory::
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/app_time_test_utils.cc b/chrome/browser/chromeos/child_accounts/time_limits/app_time_test_utils.cc
index 6e71c27..44193257 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/app_time_test_utils.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/app_time_test_utils.cc
@@ -54,7 +54,7 @@
                       : extensions::Extension::NO_FLAGS;
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
-          base::FilePath(), extensions::Manifest::UNPACKED,
+          base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
           static_cast<base::DictionaryValue&>(manifest), flags, extension_id,
           &error);
   return extension;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index d0595b9..af76553 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -59,7 +59,7 @@
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/login/users/chrome_user_manager.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/device_settings_service.h"
 #include "chrome/browser/ash/settings/shutdown_policy_forwarder.h"
@@ -408,7 +408,7 @@
 
     DeviceSettingsService::Get()->SetSessionManager(
         SessionManagerClient::Get(),
-        OwnerSettingsServiceChromeOSFactory::GetInstance()->GetOwnerKeyUtil());
+        OwnerSettingsServiceAshFactory::GetInstance()->GetOwnerKeyUtil());
   }
 
   void CreateMachineLearningDecisionProvider() {
diff --git a/chrome/browser/chromeos/crostini/crostini_features.cc b/chrome/browser/chromeos/crostini/crostini_features.cc
index 0148778..22badcd 100644
--- a/chrome/browser/chromeos/crostini/crostini_features.cc
+++ b/chrome/browser/chromeos/crostini/crostini_features.cc
@@ -291,9 +291,7 @@
 }
 
 bool CrostiniFeatures::IsContainerUpgradeUIAllowed(Profile* profile) {
-  return g_crostini_features->IsAllowedNow(profile) &&
-         base::FeatureList::IsEnabled(
-             chromeos::features::kCrostiniWebUIUpgrader);
+  return g_crostini_features->IsAllowedNow(profile);
 }
 
 void CrostiniFeatures::CanChangeAdbSideloading(
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
index aedab99..d7cb37ce 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider_unittest.cc
@@ -18,6 +18,8 @@
 #include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace chromeos {
 
 namespace {
@@ -27,7 +29,7 @@
 
 scoped_refptr<const extensions::Extension> CreateExtensionFromValues(
     const std::string& id,
-    extensions::Manifest::Location location,
+    ManifestLocation location,
     base::DictionaryValue* values,
     int flags) {
   values->SetString(extensions::manifest_keys::kName, "test");
@@ -45,25 +47,21 @@
 scoped_refptr<const extensions::Extension> CreateRegularExtension(
     const std::string& id) {
   base::DictionaryValue values;
-  return CreateExtensionFromValues(id,
-                                   extensions::Manifest::INTERNAL,
-                                   &values,
+  return CreateExtensionFromValues(id, ManifestLocation::kInternal, &values,
                                    extensions::Extension::NO_FLAGS);
 }
 
 scoped_refptr<const extensions::Extension> CreateExternalComponentExtension() {
   base::DictionaryValue values;
   return CreateExtensionFromValues(std::string(),
-                                   extensions::Manifest::EXTERNAL_COMPONENT,
-                                   &values,
-                                   extensions::Extension::NO_FLAGS);
+                                   ManifestLocation::kExternalComponent,
+                                   &values, extensions::Extension::NO_FLAGS);
 }
 
 scoped_refptr<const extensions::Extension> CreateComponentExtension() {
   base::DictionaryValue values;
-  return CreateExtensionFromValues(std::string(),
-                                   extensions::Manifest::COMPONENT, &values,
-                                   extensions::Extension::NO_FLAGS);
+  return CreateExtensionFromValues(std::string(), ManifestLocation::kComponent,
+                                   &values, extensions::Extension::NO_FLAGS);
 }
 
 scoped_refptr<const extensions::Extension> CreateHostedApp() {
@@ -72,15 +70,13 @@
              std::make_unique<base::DictionaryValue>());
   values.Set(extensions::manifest_keys::kWebURLs,
              std::make_unique<base::ListValue>());
-  return CreateExtensionFromValues(std::string(),
-                                   extensions::Manifest::INTERNAL,
-                                   &values,
-                                   extensions::Extension::NO_FLAGS);
+  return CreateExtensionFromValues(std::string(), ManifestLocation::kInternal,
+                                   &values, extensions::Extension::NO_FLAGS);
 }
 
 scoped_refptr<const extensions::Extension> CreatePlatformAppWithExtraValues(
     const base::DictionaryValue* extra_values,
-    extensions::Manifest::Location location,
+    ManifestLocation location,
     int flags) {
   base::DictionaryValue values;
   values.SetString("app.background.page", "background.html");
@@ -90,8 +86,7 @@
 
 scoped_refptr<const extensions::Extension> CreatePlatformApp() {
   base::DictionaryValue values;
-  return CreatePlatformAppWithExtraValues(&values,
-                                          extensions::Manifest::INTERNAL,
+  return CreatePlatformAppWithExtraValues(&values, ManifestLocation::kInternal,
                                           extensions::Extension::NO_FLAGS);
 }
 
@@ -149,8 +144,7 @@
   {
     base::DictionaryValue values;
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -164,8 +158,7 @@
   {
     base::DictionaryValue values;
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD,
+        &values, ManifestLocation::kExternalPolicyDownload,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -179,9 +172,7 @@
   {
     base::DictionaryValue values;
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::UNPACKED,
-        extensions::Extension::NO_FLAGS);
+        &values, ManifestLocation::kUnpacked, extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
     EXPECT_FALSE(provider.UserMayLoad(extension.get(), &error));
@@ -204,8 +195,7 @@
     values.Set(extensions::manifest_keys::kOptionalPermissions,
                std::move(optional_permissions));
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -220,8 +210,7 @@
     base::DictionaryValue values;
     values.SetString("not_whitelisted", "something");
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -239,8 +228,7 @@
     values.Set("chrome_settings_overrides",
                std::make_unique<base::DictionaryValue>());
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -255,8 +243,7 @@
     base::DictionaryValue values;
     values.SetString("app.not_whitelisted2", "something2");
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -271,8 +258,7 @@
     base::DictionaryValue values;
     values.SetString("app.content_security_policy", "something2");
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -291,9 +277,7 @@
                std::make_unique<base::ListValue>());
     values.SetString("app.content_security_policy", "something2");
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -309,9 +293,7 @@
     values.Set("theme", std::make_unique<base::DictionaryValue>());
     values.SetString("app.content_security_policy", "something2");
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -329,8 +311,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -349,8 +330,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -369,8 +349,7 @@
                std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -389,8 +368,7 @@
     values.SetString("url_handlers.example_com.title", "example title");
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -409,8 +387,7 @@
     values.SetString("url_handlers.example_com.title", "example title");
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::FROM_WEBSTORE);
     ASSERT_TRUE(extension);
 
@@ -429,8 +406,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -449,9 +425,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -468,8 +442,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -491,8 +464,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -514,8 +486,7 @@
     values.Set(extensions::manifest_keys::kPermissions, std::move(permissions));
 
     extension = CreatePlatformAppWithExtraValues(
-        &values,
-        extensions::Manifest::EXTERNAL_POLICY,
+        &values, ManifestLocation::kExternalPolicy,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -528,9 +499,7 @@
   {
     base::DictionaryValue values;
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -544,9 +513,7 @@
     base::DictionaryValue values;
     values.Set("export.whitelist", std::make_unique<base::ListValue>());
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -560,9 +527,7 @@
     base::DictionaryValue values;
     values.Set("theme", std::make_unique<base::DictionaryValue>());
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
@@ -577,9 +542,7 @@
     base::DictionaryValue values;
     values.SetString("app.launch.local_path", "something");
     extension = CreateExtensionFromValues(
-        std::string(),
-        extensions::Manifest::EXTERNAL_POLICY,
-        &values,
+        std::string(), ManifestLocation::kExternalPolicy, &values,
         extensions::Extension::NO_FLAGS);
     ASSERT_TRUE(extension);
 
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
index 80f5edfb..15d49f9 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_api.cc
@@ -12,8 +12,8 @@
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/browser_process.h"
@@ -52,7 +52,7 @@
 
 bool IsOwnerProfile(Profile* profile) {
   return profile &&
-         ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile)
+         ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile)
              ->IsOwner();
 }
 
@@ -140,9 +140,8 @@
         std::make_unique<base::Value>(user->GetAccountId().GetUserEmail()));
   }
 
-  if (ash::OwnerSettingsServiceChromeOS* service =
-          ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
-              profile)) {
+  if (ash::OwnerSettingsServiceAsh* service =
+          ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile)) {
     service->Set(chromeos::kAccountsPrefUsers, *email_list.get());
   }
 
diff --git a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
index c1f40e7..6af9e484 100644
--- a/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/users_private/users_private_apitest.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ash/login/lock/screen_locker.h"
 #include "chrome/browser/ash/login/lock/screen_locker_tester.h"
 #include "chrome/browser/ash/login/test/oobe_base_test.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
 #include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/chromeos/extensions/users_private/users_private_delegate.h"
@@ -116,12 +116,12 @@
  public:
   UsersPrivateApiTest() {
     // Mock owner key pairs. Note this needs to happen before
-    // OwnerSettingsServiceChromeOS is created.
+    // OwnerSettingsServiceAsh is created.
     scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util =
         new ownership::MockOwnerKeyUtil();
     owner_key_util->SetPrivateKey(crypto::RSAPrivateKey::Create(512));
 
-    ash::OwnerSettingsServiceChromeOSFactory::GetInstance()
+    ash::OwnerSettingsServiceAshFactory::GetInstance()
         ->SetOwnerKeyUtilForTesting(owner_key_util);
 
     scoped_testing_cros_settings_.device_settings()->Set(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc
deleted file mode 100644
index 17a6180..0000000
--- a/chrome/browser/chromeos/file_manager/file_manager_base_jstest.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2018 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/chromeos/file_manager/file_manager_jstest_base.h"
-#include "content/public/test/browser_test.h"
-
-class FileManagerBaseJsTest : public FileManagerJsTestBase {
- protected:
-  FileManagerBaseJsTest()
-      : FileManagerJsTestBase(
-            base::FilePath(FILE_PATH_LITERAL("ui/file_manager/base/js"))) {}
-};
-
-IN_PROC_BROWSER_TEST_F(FileManagerBaseJsTest, VolumeManagerTypesTest) {
-  RunTestURL("volume_manager_types_unittest.m_gen.html");
-}
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index c8815f15..9813241b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -977,6 +977,7 @@
                       TestCase("fileListKeyboardSelectionA11y"),
                       TestCase("fileListMouseSelectionA11y"),
                       TestCase("fileListDeleteMultipleFiles"),
+                      TestCase("fileListRenameSelectedItem"),
                       TestCase("fileListRenameFromSelectAll")));
 
 WRAPPED_INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 35e0feae..1c3b010 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -257,3 +257,7 @@
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, VolumeManagerTest) {
   RunTestURL("background/js/volume_manager_unittest.m_gen.html");
 }
+
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, VolumeManagerTypesTest) {
+  RunTestURL("common/js/volume_manager_types_unittest.m_gen.html");
+}
diff --git a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
index 9ba0e55..cb7fefe 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_string_util.cc
@@ -1038,9 +1038,6 @@
                    crostini::CrostiniFeatures::Get()->IsEnabled(profile));
   dict->SetBoolean("PLUGIN_VM_ENABLED",
                    plugin_vm::PluginVmFeatures::Get()->IsEnabled(profile));
-  dict->SetBoolean(
-      "FILES_CAMERA_FOLDER_ENABLED",
-      base::FeatureList::IsEnabled(chromeos::features::kFilesCameraFolder));
   dict->SetBoolean("FILES_NG_ENABLED",
                    base::FeatureList::IsEnabled(chromeos::features::kFilesNG));
   dict->SetBoolean("COPY_IMAGE_ENABLED",
diff --git a/chrome/browser/chromeos/file_system_provider/service_unittest.cc b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
index be7e4ce7a..86c0211b 100644
--- a/chrome/browser/chromeos/file_system_provider/service_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/service_unittest.cc
@@ -80,8 +80,8 @@
 
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
-          base::FilePath(), extensions::Manifest::UNPACKED, manifest,
-          extensions::Extension::NO_FLAGS, extension_id, &error);
+          base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
+          manifest, extensions::Extension::NO_FLAGS, extension_id, &error);
   EXPECT_TRUE(extension) << error;
   return extension;
 }
diff --git a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
index 6d93e5a..c11426e 100644
--- a/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
+++ b/chrome/browser/chromeos/full_restore/full_restore_arc_task_handler.h
@@ -20,8 +20,6 @@
 //
 // FullRestoreArcTaskHandler is an independent KeyedService so that it could be
 // created along with ARC system rather than with FullRestoreService.
-//
-// TODO(crbug.com/1146900): Handle intent.
 class FullRestoreArcTaskHandler : public KeyedService,
                                   public ArcAppListPrefs::Observer {
  public:
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.cc b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
index 42cb234..aa6318d 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -138,6 +138,16 @@
   UMA_HISTOGRAM_ENUMERATION("InputMethod.Mojo.Extension.Event", event);
 }
 
+ime::mojom::PhysicalKeyEventPtr CreatePhysicalKeyEventFromKeyEvent(
+    const ui::KeyEvent& event) {
+  return ime::mojom::PhysicalKeyEvent::New(
+      event.type() == ui::ET_KEY_PRESSED ? ime::mojom::KeyEventType::kKeyDown
+                                         : ime::mojom::KeyEventType::kKeyUp,
+      ui::KeycodeConverter::DomCodeToCodeString(event.code()),
+      ui::KeycodeConverter::DomKeyToKeyString(event.GetDomKey()),
+      ModifierStateFromEvent(event));
+}
+
 }  // namespace
 
 NativeInputMethodEngine::NativeInputMethodEngine() = default;
@@ -322,21 +332,34 @@
     std::move(callback).Run(true);
     return;
   }
-  auto key_event = ime::mojom::PhysicalKeyEvent::New(
-      event.type() == ui::ET_KEY_PRESSED ? ime::mojom::KeyEventType::kKeyDown
-                                         : ime::mojom::KeyEventType::kKeyUp,
-      ui::KeycodeConverter::DomCodeToCodeString(event.code()),
-      ui::KeycodeConverter::DomKeyToKeyString(event.GetDomKey()),
-      ModifierStateFromEvent(event));
 
   if (ShouldRouteToRuleBasedEngine(engine_id) && remote_to_engine_.is_bound()) {
     remote_to_engine_->ProcessKeypressForRulebased(
-        std::move(key_event),
+        CreatePhysicalKeyEventFromKeyEvent(event),
         base::BindOnce(&ImeObserver::OnRuleBasedKeyEventResponse,
                        base::Unretained(this), base::Time::Now(),
                        std::move(callback)));
   } else if (ShouldRouteToFstMojoEngine(engine_id)) {
     if (remote_to_engine_.is_bound()) {
+      // CharacterComposer only takes KEY_PRESSED events.
+      const bool filtered = event.type() == ui::ET_KEY_PRESSED &&
+                            character_composer_.FilterKeyPress(event);
+
+      // Don't send dead keys to the system IME. Dead keys should be handled at
+      // the OS level and not exposed to IMEs.
+      if (event.GetDomKey().IsDeadKey()) {
+        std::move(callback).Run(true);
+        return;
+      }
+
+      auto key_event = CreatePhysicalKeyEventFromKeyEvent(event);
+      if (filtered) {
+        // TODO(b/174612548): Transform the corresponding KEY_RELEASED event to
+        // use the composed character as well.
+        key_event->key =
+            base::UTF16ToUTF8(character_composer_.composed_character());
+      }
+
       remote_to_engine_->OnKeyEvent(std::move(key_event), std::move(callback));
     } else {
       std::move(callback).Run(false);
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.h b/chrome/browser/chromeos/input_method/native_input_method_engine.h
index b3b713b..03e0e45 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.h
@@ -14,6 +14,7 @@
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "mojo/public/cpp/bindings/remote.h"
+#include "ui/base/ime/character_composer.h"
 
 namespace chromeos {
 
@@ -171,6 +172,8 @@
 
     std::unique_ptr<AssistiveSuggester> assistive_suggester_;
     std::unique_ptr<AutocorrectManager> autocorrect_manager_;
+
+    ui::CharacterComposer character_composer_;
   };
 
   ImeObserver* GetNativeObserver() const;
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
index 298a3b8..cd82f04 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine_unittest.cc
@@ -22,6 +22,7 @@
 #include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
 #include "ui/base/ime/chromeos/mock_input_method_manager.h"
 #include "ui/base/ime/text_input_flags.h"
+#include "ui/events/keycodes/dom/dom_code.h"
 
 namespace chromeos {
 namespace {
@@ -32,6 +33,7 @@
 
 using input_method::InputMethodManager;
 using input_method::StubInputMethodEngineObserver;
+using testing::_;
 using testing::NiceMock;
 using testing::StrictMock;
 
@@ -268,7 +270,7 @@
   {
     testing::InSequence seq;
     EXPECT_CALL(mock_input_channel, OnInputMethodChanged(kEngineIdUs));
-    EXPECT_CALL(mock_input_channel, OnFocus(::testing::_));
+    EXPECT_CALL(mock_input_channel, OnFocus(_));
     // Each character in "你好" is three UTF-8 code units.
     EXPECT_CALL(mock_input_channel,
                 OnSurroundingTextChanged(u8"你好",
@@ -292,5 +294,59 @@
   InputMethodManager::Shutdown();
 }
 
+TEST_F(NativeInputMethodEngineTest, ProcessesDeadKeysCorrectly) {
+  TestingProfile testing_profile;
+  SetPhysicalTypingAutocorrectEnabled(testing_profile, true);
+
+  testing::StrictMock<ime::MockInputChannel> mock_input_channel;
+  input_method::InputMethodManager::Initialize(
+      new TestInputMethodManager(&mock_input_channel));
+  ui::MockIMEInputContextHandler mock_handler;
+  ui::IMEBridge::Get()->SetInputContextHandler(&mock_handler);
+  NativeInputMethodEngine engine;
+  engine.Initialize(std::make_unique<StubInputMethodEngineObserver>(),
+                    /*extension_id=*/"", &testing_profile);
+
+  {
+    testing::InSequence seq;
+    EXPECT_CALL(mock_input_channel, OnInputMethodChanged(kEngineIdUs));
+    EXPECT_CALL(mock_input_channel, OnFocus(_));
+
+    // TODO(https://crbug.com/1187982): Expect the actual arguments to the call
+    // once the Mojo API is replaced with protos. GMock does not play well with
+    // move-only types like PhysicalKeyEvent.
+    EXPECT_CALL(mock_input_channel, OnKeyEvent(_, _))
+        .Times(2)
+        .WillRepeatedly(::testing::Invoke(
+            [](ime::mojom::PhysicalKeyEventPtr,
+               ime::mojom::InputChannel::OnKeyEventCallback callback) {
+              std::move(callback).Run(false);
+            }));
+  }
+
+  engine.Enable(kEngineIdUs);
+  engine.FocusIn(ui::IMEEngineHandlerInterface::InputContext(
+      ui::TEXT_INPUT_TYPE_TEXT, ui::TEXT_INPUT_MODE_DEFAULT,
+      ui::TEXT_INPUT_FLAG_NONE, ui::TextInputClient::FOCUS_REASON_MOUSE,
+      /*should_do_learning=*/true));
+
+  // Quote ("VKEY_OEM_7") + A is a dead key combination.
+  engine.ProcessKeyEvent(
+      {ui::ET_KEY_PRESSED, ui::VKEY_OEM_7, ui::DomCode::QUOTE, ui::EF_NONE,
+       ui::DomKey::DeadKeyFromCombiningCharacter(u'\u0301'), base::TimeTicks()},
+      base::DoNothing());
+  engine.ProcessKeyEvent(
+      {ui::ET_KEY_RELEASED, ui::VKEY_OEM_7, ui::DomCode::QUOTE, ui::EF_NONE,
+       ui::DomKey::DeadKeyFromCombiningCharacter(u'\u0301'), base::TimeTicks()},
+      base::DoNothing());
+  engine.ProcessKeyEvent({ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE},
+                         base::DoNothing());
+  engine.ProcessKeyEvent({ui::ET_KEY_RELEASED, ui::VKEY_A, ui::EF_NONE},
+                         base::DoNothing());
+  engine.FlushForTesting();
+
+  InputMethodManager::Shutdown();
+}
+
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl.cc b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl.cc
index 8e160fc..c66aca2 100644
--- a/chrome/browser/chromeos/lock_screen_apps/app_manager_impl.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/app_manager_impl.cc
@@ -409,9 +409,11 @@
 
   std::string error;
   scoped_refptr<extensions::Extension> lock_profile_app =
-      extensions::Extension::Create(lock_profile_app_path, app->location(),
-                                    *app->manifest()->value()->CreateDeepCopy(),
-                                    app->creation_flags(), app->id(), &error);
+      extensions::Extension::Create(
+          lock_profile_app_path,
+          static_cast<extensions::mojom::ManifestLocation>(app->location()),
+          *app->manifest()->value()->CreateDeepCopy(), app->creation_flags(),
+          app->id(), &error);
 
   // While extension creation can fail in general, in this case the lock screen
   // profile extension creation arguments come from an app already installed in
@@ -552,9 +554,11 @@
 
   std::string error;
   scoped_refptr<extensions::Extension> lock_profile_app =
-      extensions::Extension::Create(app->path(), app->location(),
-                                    *app->manifest()->value()->CreateDeepCopy(),
-                                    app->creation_flags(), app->id(), &error);
+      extensions::Extension::Create(
+          app->path(),
+          static_cast<extensions::mojom::ManifestLocation>(app->location()),
+          *app->manifest()->value()->CreateDeepCopy(), app->creation_flags(),
+          app->id(), &error);
 
   extensions::ExtensionService* extension_service =
       extensions::ExtensionSystem::Get(lock_screen_profile_)
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate.h b/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate.h
index 231c7fd7..e10366e 100644
--- a/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate.h
+++ b/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate.h
@@ -75,8 +75,7 @@
 // 3- app A is mentioned in KeyPermissions user policy.
 class UserPrivateTokenArcKpmDelegate : public ArcKpmDelegate,
                                        public arc::ArcSessionManagerObserver,
-                                       public ArcAppListPrefs::Observer,
-                                       public base::CheckedObserver {
+                                       public ArcAppListPrefs::Observer {
  public:
   explicit UserPrivateTokenArcKpmDelegate(Profile* profile);
   UserPrivateTokenArcKpmDelegate(const UserPrivateTokenArcKpmDelegate&) =
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index df9bd1f..0e794be6 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -20,8 +20,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/device_settings_test_helper.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
@@ -550,8 +550,8 @@
             device_management_service_.StartJobFullControl(&register_job)));
     AllowUninterestingRemoteCommandFetches();
 
-    ash::OwnerSettingsServiceChromeOS* owner_settings_service =
-        ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+    ash::OwnerSettingsServiceAsh* owner_settings_service =
+        ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(
             profile_.get());
     ASSERT_TRUE(owner_settings_service);
 
diff --git a/chrome/browser/chromeos/policy/device_local_account.cc b/chrome/browser/chromeos/policy/device_local_account.cc
index 2aafbed0..3c73d210 100644
--- a/chrome/browser/chromeos/policy/device_local_account.cc
+++ b/chrome/browser/chromeos/policy/device_local_account.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/account_id/account_id.h"
@@ -174,7 +174,7 @@
   return true;
 }
 
-void SetDeviceLocalAccounts(ash::OwnerSettingsServiceChromeOS* service,
+void SetDeviceLocalAccounts(ash::OwnerSettingsServiceAsh* service,
                             const std::vector<DeviceLocalAccount>& accounts) {
   // TODO(https://crbug.com/984021): handle TYPE_SAML_PUBLIC_SESSION
   base::ListValue list;
diff --git a/chrome/browser/chromeos/policy/device_local_account.h b/chrome/browser/chromeos/policy/device_local_account.h
index 94b0fa3d..f0366de 100644
--- a/chrome/browser/chromeos/policy/device_local_account.h
+++ b/chrome/browser/chromeos/policy/device_local_account.h
@@ -10,7 +10,7 @@
 
 namespace ash {
 class CrosSettings;
-class OwnerSettingsServiceChromeOS;
+class OwnerSettingsServiceAsh;
 }  // namespace ash
 
 namespace policy {
@@ -123,7 +123,7 @@
 // Stores a list of device-local accounts in |service|. The accounts are stored
 // as a list of dictionaries with each dictionary containing the information
 // about one |DeviceLocalAccount|.
-void SetDeviceLocalAccounts(ash::OwnerSettingsServiceChromeOS* service,
+void SetDeviceLocalAccounts(ash::OwnerSettingsServiceAsh* service,
                             const std::vector<DeviceLocalAccount>& accounts);
 
 // Retrieves a list of device-local accounts from |cros_settings|.
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index f0e16eb9..50643bc 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -19,7 +19,7 @@
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/ash/login/enrollment/auto_enrollment_controller.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/active_directory_join_delegate.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
diff --git a/chrome/browser/chromeos/ui/idle_app_name_notification_view_unittest.cc b/chrome/browser/chromeos/ui/idle_app_name_notification_view_unittest.cc
index e2833b7..26a5c85 100644
--- a/chrome/browser/chromeos/ui/idle_app_name_notification_view_unittest.cc
+++ b/chrome/browser/chromeos/ui/idle_app_name_notification_view_unittest.cc
@@ -42,25 +42,17 @@
     manifest.SetString("author.email", "Someone");
 
     std::string error;
-    correct_extension_ =
-        extensions::Extension::Create(base::FilePath(),
-                                      extensions::Manifest::UNPACKED,
-                                      manifest,
-                                      extensions::Extension::NO_FLAGS,
-                                      kTestAppName,
-                                      &error);
+    correct_extension_ = extensions::Extension::Create(
+        base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
+        manifest, extensions::Extension::NO_FLAGS, kTestAppName, &error);
     base::DictionaryValue manifest2;
     manifest2.SetString(extensions::manifest_keys::kName, "Test");
     manifest2.SetString(extensions::manifest_keys::kVersion, "1");
     manifest2.SetString(extensions::manifest_keys::kDescription, "Test app");
 
-    incorrect_extension_ =
-        extensions::Extension::Create(base::FilePath(),
-                                      extensions::Manifest::UNPACKED,
-                                      manifest2,
-                                      extensions::Extension::NO_FLAGS,
-                                      kTestAppName,
-                                      &error);
+    incorrect_extension_ = extensions::Extension::Create(
+        base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
+        manifest2, extensions::Extension::NO_FLAGS, kTestAppName, &error);
   }
 
   void TearDown() override {
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 4f3f9f8..729e146 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -647,8 +647,6 @@
     "menu_manager_factory.h",
     "navigation_observer.cc",
     "navigation_observer.h",
-    "ntp_overridden_bubble_delegate.cc",
-    "ntp_overridden_bubble_delegate.h",
     "pack_extension_job.cc",
     "pack_extension_job.h",
     "pending_extension_info.cc",
diff --git a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
index a992b6bb..6cc902d 100644
--- a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
+++ b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
@@ -29,7 +29,7 @@
 #include "chrome/browser/ash/crosapi/automation_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_ash.h"
 #include "chrome/browser/ash/crosapi/crosapi_manager.h"
-#include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h"
+#include "chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge.h"
 #endif
 
 namespace extensions {
diff --git a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
index e738d4b..cd638e08a 100644
--- a/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
+++ b/chrome/browser/extensions/api/mdns/mdns_api_unittest.cc
@@ -231,11 +231,8 @@
     std::string error;
     return extensions::Extension::Create(
         bogus_file_pathname(name),
-        extensions::Manifest::INVALID_LOCATION,
-        manifest,
-        Extension::NO_FLAGS,
-        extension_id,
-        &error);
+        extensions::mojom::ManifestLocation::kInvalidLocation, manifest,
+        Extension::NO_FLAGS, extension_id, &error);
   }
 
   content::RenderProcessHost* render_process_host() const {
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
index fd0cade8d..0f505cf8 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_launch_from_native_unittest.cc
@@ -106,9 +106,9 @@
     EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path));
 
     std::string error;
-    scoped_refptr<Extension> extension(
-        Extension::Create(path, Manifest::INTERNAL, *manifest_builder.Build(),
-                          Extension::NO_FLAGS, &error));
+    scoped_refptr<Extension> extension(Extension::Create(
+        path, mojom::ManifestLocation::kInternal, *manifest_builder.Build(),
+        Extension::NO_FLAGS, &error));
     ASSERT_TRUE(extension.get()) << error;
     ExtensionRegistry::Get(&profile_)->AddEnabled(extension);
     extension_id_ = extension->id();
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index d69d4cb..1a12940 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -57,8 +57,8 @@
 #include "ash/constants/ash_pref_names.h"
 #include "ash/public/cpp/ambient/ambient_prefs.h"
 #include "ash/public/cpp/ash_pref_names.h"  // nogncheck
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_pref_names.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
@@ -1048,8 +1048,8 @@
     return settings_private::SetPrefResult::PREF_NOT_MODIFIABLE;
   }
 
-  ash::OwnerSettingsServiceChromeOS* service =
-      ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_);
+  ash::OwnerSettingsServiceAsh* service =
+      ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_);
 
   if (service && service->HandlesSetting(pref_name) &&
       service->Set(pref_name, *value)) {
@@ -1065,8 +1065,8 @@
 bool PrefsUtil::AppendToListCrosSetting(const std::string& pref_name,
                                         const base::Value& value) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  ash::OwnerSettingsServiceChromeOS* service =
-      ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_);
+  ash::OwnerSettingsServiceAsh* service =
+      ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_);
 
   return service && service->HandlesSetting(pref_name) &&
          service->AppendToList(pref_name, value);
@@ -1079,8 +1079,8 @@
 bool PrefsUtil::RemoveFromListCrosSetting(const std::string& pref_name,
                                           const base::Value& value) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  ash::OwnerSettingsServiceChromeOS* service =
-      ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile_);
+  ash::OwnerSettingsServiceAsh* service =
+      ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile_);
 
   return service && service->HandlesSetting(pref_name) &&
          service->RemoveFromList(pref_name, value);
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
index 6e0b2fc..d4cdfc2 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc
@@ -1201,7 +1201,7 @@
 
   std::string error;
   auto dummy_extension =
-      Extension::Create(base::FilePath(), Manifest::INTERNAL,
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
                         base::Value::AsDictionaryValue(*result.value),
                         Extension::FROM_WEBSTORE, extension_id, &error);
 
diff --git a/chrome/browser/extensions/chrome_app_sorting_unittest.cc b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
index f29144f..1a75eec 100644
--- a/chrome/browser/extensions/chrome_app_sorting_unittest.cc
+++ b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
@@ -15,6 +15,8 @@
 #include "extensions/common/manifest_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace keys = manifest_keys;
@@ -586,17 +588,17 @@
     simple_dict.SetString(keys::kLaunchLocalPath, "fake.html");
 
     std::string error;
-    app1_scoped_ = Extension::Create(
-        prefs_.temp_dir().AppendASCII("app1_"), Manifest::EXTERNAL_PREF,
-        simple_dict, Extension::NO_FLAGS, &error);
+    app1_scoped_ = Extension::Create(prefs_.temp_dir().AppendASCII("app1_"),
+                                     ManifestLocation::kExternalPref,
+                                     simple_dict, Extension::NO_FLAGS, &error);
     prefs()->OnExtensionInstalled(app1_scoped_.get(),
                                   Extension::ENABLED,
                                   syncer::StringOrdinal(),
                                   std::string());
 
-    app2_scoped_ = Extension::Create(
-        prefs_.temp_dir().AppendASCII("app2_"), Manifest::EXTERNAL_PREF,
-        simple_dict, Extension::NO_FLAGS, &error);
+    app2_scoped_ = Extension::Create(prefs_.temp_dir().AppendASCII("app2_"),
+                                     ManifestLocation::kExternalPref,
+                                     simple_dict, Extension::NO_FLAGS, &error);
     prefs()->OnExtensionInstalled(app2_scoped_.get(),
                                   Extension::ENABLED,
                                   syncer::StringOrdinal(),
@@ -756,7 +758,7 @@
 
     std::string errors;
     scoped_refptr<Extension> app = Extension::Create(
-        prefs_.temp_dir().AppendASCII(name), Manifest::EXTERNAL_PREF,
+        prefs_.temp_dir().AppendASCII(name), ManifestLocation::kExternalPref,
         simple_dict, Extension::NO_FLAGS, &errors);
     EXPECT_TRUE(app.get()) << errors;
     EXPECT_TRUE(crx_file::id_util::IdIsValid(app->id()));
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
index 8d169a5..fce8e6ce 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager_unittest.cc
@@ -58,11 +58,9 @@
   resources_path = resources_path.AppendASCII("file_manager");
 
   // Create a simulated component extension.
-  scoped_refptr<Extension> extension = Extension::Create(resources_path,
-                                                         Manifest::COMPONENT,
-                                                         *manifest,
-                                                         Extension::NO_FLAGS,
-                                                         &error);
+  scoped_refptr<Extension> extension =
+      Extension::Create(resources_path, mojom::ManifestLocation::kComponent,
+                        *manifest, Extension::NO_FLAGS, &error);
   ASSERT_TRUE(extension.get());
 
   // Load one of the icons.
diff --git a/chrome/browser/extensions/chrome_info_map_unittest.cc b/chrome/browser/extensions/chrome_info_map_unittest.cc
index e2d1685a..4a3d23ca 100644
--- a/chrome/browser/extensions/chrome_info_map_unittest.cc
+++ b/chrome/browser/extensions/chrome_info_map_unittest.cc
@@ -29,11 +29,9 @@
 
   std::string error;
   scoped_refptr<Extension> extension =
-      Extension::Create(path,
-                        Manifest::INVALID_LOCATION,
+      Extension::Create(path, mojom::ManifestLocation::kInvalidLocation,
                         *static_cast<base::DictionaryValue*>(result.get()),
-                        Extension::NO_FLAGS,
-                        &error);
+                        Extension::NO_FLAGS, &error);
   EXPECT_TRUE(extension.get()) << error;
 
   return extension;
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index 2a3890a..148f416c 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -439,8 +439,9 @@
   // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
   //               our component extensions to the new manifest version.
   int flags = Extension::REQUIRE_KEY;
-  return Extension::Create(info.root_directory, Manifest::COMPONENT,
-                           *info.manifest, flags, utf8_error);
+  return Extension::Create(info.root_directory,
+                           mojom::ManifestLocation::kComponent, *info.manifest,
+                           flags, utf8_error);
 }
 
 // static
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 2d1e153..dbdba81 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -171,8 +171,8 @@
   // with std::u16string
   std::string utf8_error;
   scoped_refptr<Extension> extension =
-      Extension::Create(temp_dir.GetPath(), Manifest::INTERNAL, *root,
-                        Extension::NO_FLAGS, &utf8_error);
+      Extension::Create(temp_dir.GetPath(), mojom::ManifestLocation::kInternal,
+                        *root, Extension::NO_FLAGS, &utf8_error);
   *error = base::UTF8ToUTF16(utf8_error);
   if (!extension.get()) {
     NOTREACHED() << "Could not init extension " << *error;
diff --git a/chrome/browser/extensions/convert_web_app.cc b/chrome/browser/extensions/convert_web_app.cc
index 64909d6f..ca20046c 100644
--- a/chrome/browser/extensions/convert_web_app.cc
+++ b/chrome/browser/extensions/convert_web_app.cc
@@ -211,7 +211,7 @@
     const base::Time& create_time,
     const base::FilePath& extensions_dir,
     int extra_creation_flags,
-    Manifest::Location install_source) {
+    mojom::ManifestLocation install_source) {
   base::FilePath install_temp_dir =
       file_util::GetInstallTempDir(extensions_dir);
   if (install_temp_dir.empty()) {
diff --git a/chrome/browser/extensions/convert_web_app.h b/chrome/browser/extensions/convert_web_app.h
index e1f0ab0..0955c00 100644
--- a/chrome/browser/extensions/convert_web_app.h
+++ b/chrome/browser/extensions/convert_web_app.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 
 namespace base {
 class DictionaryValue;
@@ -74,7 +75,7 @@
     const base::Time& create_time,
     const base::FilePath& extensions_dir,
     int extra_creation_flags,
-    Manifest::Location install_source);
+    mojom::ManifestLocation install_source);
 
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index 1101bb7e..0059f79e 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -49,6 +49,8 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "url/gurl.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace keys = manifest_keys;
@@ -154,7 +156,7 @@
 
   std::string error;
   scoped_refptr<Extension> bookmark_app =
-      Extension::Create(ExtensionPath(), Manifest::INTERNAL, manifest,
+      Extension::Create(ExtensionPath(), ManifestLocation::kInternal, manifest,
                         Extension::FROM_BOOKMARK, &error);
   ASSERT_TRUE(bookmark_app.get());
 
@@ -172,7 +174,7 @@
 
   std::string error;
   scoped_refptr<Extension> bookmark_app =
-      Extension::Create(ExtensionPath(), Manifest::INTERNAL, manifest,
+      Extension::Create(ExtensionPath(), ManifestLocation::kInternal, manifest,
                         Extension::FROM_BOOKMARK, &error);
   ASSERT_TRUE(bookmark_app.get());
 
@@ -207,7 +209,7 @@
 
   std::string error;
   scoped_refptr<Extension> bookmark_app =
-      Extension::Create(ExtensionPath(), Manifest::INTERNAL, manifest,
+      Extension::Create(ExtensionPath(), ManifestLocation::kInternal, manifest,
                         Extension::FROM_BOOKMARK, &error);
   ASSERT_TRUE(bookmark_app.get());
 
@@ -250,7 +252,7 @@
 
   std::string error;
   scoped_refptr<Extension> bookmark_app =
-      Extension::Create(ExtensionPath(), Manifest::INTERNAL, manifest,
+      Extension::Create(ExtensionPath(), ManifestLocation::kInternal, manifest,
                         Extension::FROM_BOOKMARK, &error);
   ASSERT_TRUE(bookmark_app.get());
 
@@ -293,7 +295,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::INTERNAL);
+      Extension::NO_FLAGS, ManifestLocation::kInternal);
   ASSERT_TRUE(extension.get());
 
   base::ScopedTempDir extension_dir;
@@ -307,7 +309,8 @@
   EXPECT_FALSE(extension->was_installed_by_default());
   EXPECT_FALSE(extension->was_installed_by_oem());
   EXPECT_FALSE(extension->from_webstore());
-  EXPECT_EQ(Manifest::INTERNAL, extension->location());
+  EXPECT_EQ(ManifestLocation::kInternal,
+            static_cast<ManifestLocation>(extension->location()));
 
   EXPECT_EQ("zVvdNZy3Mp7CFU8JVSyXNlDuHdVLbP7fDO3TGVzj/0w=",
             extension->public_key());
@@ -353,7 +356,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::INTERNAL);
+      Extension::NO_FLAGS, ManifestLocation::kInternal);
   ASSERT_TRUE(extension.get());
 
   base::ScopedTempDir extension_dir;
@@ -367,7 +370,8 @@
   EXPECT_FALSE(extension->was_installed_by_default());
   EXPECT_FALSE(extension->was_installed_by_oem());
   EXPECT_FALSE(extension->from_webstore());
-  EXPECT_EQ(Manifest::INTERNAL, extension->location());
+  EXPECT_EQ(ManifestLocation::kInternal,
+            static_cast<ManifestLocation>(extension->location()));
 
   EXPECT_EQ("zVvdNZy3Mp7CFU8JVSyXNlDuHdVLbP7fDO3TGVzj/0w=",
             extension->public_key());
@@ -393,7 +397,7 @@
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
       Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_OEM,
-      Manifest::INTERNAL);
+      ManifestLocation::kInternal);
   ASSERT_TRUE(extension.get());
 
   EXPECT_TRUE(extension->is_app());
@@ -404,7 +408,8 @@
   EXPECT_TRUE(extension->was_installed_by_oem());
   EXPECT_TRUE(extension->from_webstore());
   EXPECT_FALSE(extension->was_installed_by_default());
-  EXPECT_EQ(Manifest::INTERNAL, extension->location());
+  EXPECT_EQ(ManifestLocation::kInternal,
+            static_cast<ManifestLocation>(extension->location()));
 }
 
 TEST_F(ExtensionFromWebApp, ExternalPolicyLocation) {
@@ -415,7 +420,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::EXTERNAL_POLICY);
+      Extension::NO_FLAGS, ManifestLocation::kExternalPolicy);
   ASSERT_TRUE(extension.get());
 
   EXPECT_TRUE(extension->is_app());
@@ -440,7 +445,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::INTERNAL);
+      Extension::NO_FLAGS, ManifestLocation::kInternal);
   ASSERT_TRUE(extension.get());
   EXPECT_EQ(web_app.scope, GetScopeURLFromBookmarkApp(extension.get()));
 }
@@ -475,7 +480,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::INTERNAL);
+      Extension::NO_FLAGS, ManifestLocation::kInternal);
 
   ASSERT_TRUE(extension.get());
 
@@ -538,7 +543,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::NO_FLAGS, Manifest::INTERNAL);
+      Extension::NO_FLAGS, ManifestLocation::kInternal);
 
   ASSERT_TRUE(extension.get());
 
@@ -617,7 +622,7 @@
 
   scoped_refptr<Extension> extension = ConvertWebAppToExtension(
       web_app, GetTestTime(1978, 12, 11, 0, 0, 0, 0), ExtensionPath(),
-      Extension::FROM_BOOKMARK, Manifest::INTERNAL);
+      Extension::FROM_BOOKMARK, ManifestLocation::kInternal);
 
   ASSERT_TRUE(extension.get());
 
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 6bb7ec07..741b365 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -307,9 +307,9 @@
 
 void CrxInstaller::ConvertWebAppOnSharedFileThread(
     const WebApplicationInfo& web_app) {
-  scoped_refptr<Extension> extension(
-      ConvertWebAppToExtension(web_app, base::Time::Now(), install_directory_,
-                               creation_flags_, install_source_));
+  scoped_refptr<Extension> extension(ConvertWebAppToExtension(
+      web_app, base::Time::Now(), install_directory_, creation_flags_,
+      static_cast<mojom::ManifestLocation>(install_source_)));
   if (!extension.get()) {
     // Validation should have stopped any potential errors before getting here.
     NOTREACHED() << "Could not convert web app to extension.";
@@ -382,8 +382,9 @@
           WebstoreInstaller::MANIFEST_CHECK_LEVEL_LOOSE) {
         std::string error;
         scoped_refptr<Extension> dummy_extension = Extension::Create(
-            base::FilePath(), install_source_, *expected_manifest_,
-            creation_flags_, extension->id(), &error);
+            base::FilePath(),
+            static_cast<mojom::ManifestLocation>(install_source_),
+            *expected_manifest_, creation_flags_, extension->id(), &error);
         if (error.empty()) {
           valid = !(PermissionMessageProvider::Get()->IsPrivilegeIncrease(
               dummy_extension->permissions_data()->active_permissions(),
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
index 8819a0f5..10782eb 100644
--- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -38,6 +38,8 @@
 #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h"
 #endif
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 namespace {
 
@@ -97,7 +99,7 @@
   }
 
   scoped_refptr<Extension> CreateExtension(const char* name,
-                                           Manifest::Location location) {
+                                           ManifestLocation location) {
     // Create and load an extension.
     base::FilePath test_file;
     if (!base::PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
@@ -180,7 +182,7 @@
   // Load an extension that has browser action without default icon set in the
   // manifest and does not call |SetIcon| by default.
   scoped_refptr<Extension> extension(
-      CreateExtension("browser_action/no_icon", Manifest::UNPACKED));
+      CreateExtension("browser_action/no_icon", ManifestLocation::kUnpacked));
   ASSERT_TRUE(extension.get() != nullptr);
   ExtensionAction* action = GetExtensionAction(*extension);
   ASSERT_TRUE(action);
@@ -202,8 +204,8 @@
 TEST_F(ExtensionActionIconFactoryTest, InvisibleIcon) {
   // Load an extension that has browser action with a default icon set in the
   // manifest, but that icon is not sufficiently visible.
-  scoped_refptr<Extension> extension(
-      CreateExtension("browser_action/invisible_icon", Manifest::INTERNAL));
+  scoped_refptr<Extension> extension(CreateExtension(
+      "browser_action/invisible_icon", ManifestLocation::kInternal));
 
   // Check that the default icon is not sufficiently visible.
   ASSERT_TRUE(extension);
@@ -247,7 +249,7 @@
   // manifest and does not call |SetIcon| by default (but has an browser action
   // icon resource).
   scoped_refptr<Extension> extension(
-      CreateExtension("browser_action/no_icon", Manifest::UNPACKED));
+      CreateExtension("browser_action/no_icon", ManifestLocation::kUnpacked));
   ASSERT_TRUE(extension.get() != nullptr);
   ExtensionAction* action = GetExtensionAction(*extension);
   ASSERT_TRUE(action);
@@ -285,7 +287,7 @@
   // manifest and does not call |SetIcon| by default (but has an browser action
   // icon resource).
   scoped_refptr<Extension> extension(
-      CreateExtension("browser_action/no_icon", Manifest::UNPACKED));
+      CreateExtension("browser_action/no_icon", ManifestLocation::kUnpacked));
   ASSERT_TRUE(extension.get() != nullptr);
   ExtensionAction* action = GetExtensionAction(*extension);
   ASSERT_TRUE(action);
@@ -293,7 +295,7 @@
   ASSERT_TRUE(action->GetExplicitlySetIcon(0 /*tab id*/).IsEmpty());
 
   scoped_refptr<const Extension> extension_with_icon =
-      CreateExtension("browser_action_with_icon", Manifest::UNPACKED);
+      CreateExtension("browser_action_with_icon", ManifestLocation::kUnpacked);
   ASSERT_TRUE(extension_with_icon);
 
   int icon_size = ExtensionAction::ActionIconSize();
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index fad226d..8959eb15d 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -122,9 +122,9 @@
   ASSERT_TRUE(manifest.get() != NULL);
 
   std::string error;
-  scoped_refptr<Extension> extension(
-      Extension::Create(manifest_path.DirName(), Manifest::INVALID_LOCATION,
-                        *manifest, Extension::NO_FLAGS, &error));
+  scoped_refptr<Extension> extension(Extension::Create(
+      manifest_path.DirName(), mojom::ManifestLocation::kInvalidLocation,
+      *manifest, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get());
   ExtensionIconManager icon_manager;
   icon_manager.set_observer(this);
@@ -166,8 +166,8 @@
 
   std::string error;
   scoped_refptr<Extension> extension(Extension::Create(
-      manifest_path.DirName(), Manifest::COMPONENT, *manifest.get(),
-      Extension::NO_FLAGS, &error));
+      manifest_path.DirName(), mojom::ManifestLocation::kComponent,
+      *manifest.get(), Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get());
 
   ExtensionIconManager icon_manager;
@@ -209,9 +209,9 @@
   ASSERT_TRUE(manifest);
 
   std::string error;
-  scoped_refptr<Extension> extension(
-      Extension::Create(manifest_path.DirName(), Manifest::INVALID_LOCATION,
-                        *manifest, Extension::NO_FLAGS, &error));
+  scoped_refptr<Extension> extension(Extension::Create(
+      manifest_path.DirName(), mojom::ManifestLocation::kInvalidLocation,
+      *manifest, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension);
 
   constexpr int kMaxIconSizeInManifest = 32;
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index bc3a65da..16cfe64 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -485,7 +485,7 @@
   }
 
   return Extension::Create(
-      base::FilePath(), Manifest::INTERNAL,
+      base::FilePath(), extensions::mojom::ManifestLocation::kInternal,
       localized_manifest.get() ? *localized_manifest : *manifest, flags, id,
       error);
 }
diff --git a/chrome/browser/extensions/extension_management_unittest.cc b/chrome/browser/extensions/extension_management_unittest.cc
index c2437e7..1db458a 100644
--- a/chrome/browser/extensions/extension_management_unittest.cc
+++ b/chrome/browser/extensions/extension_management_unittest.cc
@@ -31,6 +31,8 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace {
@@ -213,15 +215,15 @@
       const std::string& id,
       const std::string& update_url) {
     scoped_refptr<const Extension> extension =
-        CreateExtension(Manifest::UNPACKED, "0.1", id, update_url);
+        CreateExtension(ManifestLocation::kUnpacked, "0.1", id, update_url);
     return extension_management_->GetInstallationMode(extension.get());
   }
 
   // Wrapper of ExtensionManagement::GetPolicyBlockedHosts, |id| is used
   // to construct an Extension for testing.
   URLPatternSet GetPolicyBlockedHosts(const std::string& id) {
-    scoped_refptr<const Extension> extension =
-        CreateExtension(Manifest::UNPACKED, "0.1", id, kNonExistingUpdateUrl);
+    scoped_refptr<const Extension> extension = CreateExtension(
+        ManifestLocation::kUnpacked, "0.1", id, kNonExistingUpdateUrl);
     return extension_management_->GetPolicyBlockedHosts(extension.get())
         .Clone();
   }
@@ -229,8 +231,8 @@
   // Wrapper of ExtensionManagement::GetPolicyAllowedHosts, |id| is used
   // to construct an Extension for testing.
   URLPatternSet GetPolicyAllowedHosts(const std::string& id) {
-    scoped_refptr<const Extension> extension =
-        CreateExtension(Manifest::UNPACKED, "0.1", id, kNonExistingUpdateUrl);
+    scoped_refptr<const Extension> extension = CreateExtension(
+        ManifestLocation::kUnpacked, "0.1", id, kNonExistingUpdateUrl);
     return extension_management_->GetPolicyAllowedHosts(extension.get())
         .Clone();
   }
@@ -246,15 +248,15 @@
   APIPermissionSet GetBlockedAPIPermissions(const std::string& id,
                                             const std::string& update_url) {
     scoped_refptr<const Extension> extension =
-        CreateExtension(Manifest::UNPACKED, "0.1", id, update_url);
+        CreateExtension(ManifestLocation::kUnpacked, "0.1", id, update_url);
     return extension_management_->GetBlockedAPIPermissions(extension.get());
   }
 
   // Wrapper of ExtensionManagement::CheckMinimumVersion, |id| and
   // |version| are used to construct an Extension for testing.
   bool CheckMinimumVersion(const std::string& id, const std::string& version) {
-    scoped_refptr<const Extension> extension =
-        CreateExtension(Manifest::UNPACKED, version, id, kNonExistingUpdateUrl);
+    scoped_refptr<const Extension> extension = CreateExtension(
+        ManifestLocation::kUnpacked, version, id, kNonExistingUpdateUrl);
     std::string minimum_version_required;
     bool ret = extension_management_->CheckMinimumVersion(
         extension.get(), &minimum_version_required);
@@ -268,7 +270,7 @@
   // Create an extension with specified |location|, |version|, |id| and
   // |update_url|.
   scoped_refptr<const Extension> CreateExtension(
-      Manifest::Location location,
+      ManifestLocation location,
       const std::string& version,
       const std::string& id,
       const std::string& update_url) {
@@ -305,12 +307,12 @@
         new StandardManagementPolicyProvider(extension_management_.get()));
   }
 
-  void CreateExtension(Manifest::Location location) {
+  void CreateExtension(ManifestLocation location) {
     base::DictionaryValue values;
     CreateExtensionFromValues(location, &values);
   }
 
-  void CreateHostedApp(Manifest::Location location) {
+  void CreateHostedApp(ManifestLocation location) {
     base::DictionaryValue values;
     values.Set(extensions::manifest_keys::kWebURLs,
                std::make_unique<base::ListValue>());
@@ -319,7 +321,7 @@
     CreateExtensionFromValues(location, &values);
   }
 
-  void CreateExtensionFromValues(Manifest::Location location,
+  void CreateExtensionFromValues(ManifestLocation location,
                                  base::DictionaryValue* values) {
     values->SetString(extensions::manifest_keys::kName, "test");
     values->SetString(extensions::manifest_keys::kVersion, "0.1");
@@ -1050,7 +1052,7 @@
 
 // Tests UserMayLoad for required extensions.
 TEST_F(ExtensionAdminPolicyTest, UserMayLoadRequired) {
-  CreateExtension(Manifest::COMPONENT);
+  CreateExtension(ManifestLocation::kComponent);
   EXPECT_TRUE(UserMayLoad(nullptr, nullptr, nullptr, nullptr, extension_.get(),
                           nullptr));
   std::u16string error;
@@ -1071,7 +1073,7 @@
 
 // Tests UserMayLoad when no blocklist exists, or it's empty.
 TEST_F(ExtensionAdminPolicyTest, UserMayLoadNoBlocklist) {
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
   EXPECT_TRUE(UserMayLoad(nullptr, nullptr, nullptr, nullptr, extension_.get(),
                           nullptr));
   base::ListValue blocklist;
@@ -1085,7 +1087,7 @@
 
 // Tests UserMayLoad for an extension on the allowlist.
 TEST_F(ExtensionAdminPolicyTest, UserMayLoadAllowlisted) {
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
 
   base::ListValue allowlist;
   allowlist.AppendString(extension_->id());
@@ -1104,7 +1106,7 @@
 
 // Tests UserMayLoad for an extension on the blocklist.
 TEST_F(ExtensionAdminPolicyTest, UserMayLoadBlocklisted) {
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
 
   // Blocklisted by default.
   base::ListValue blocklist;
@@ -1136,7 +1138,7 @@
 }
 
 TEST_F(ExtensionAdminPolicyTest, UserMayLoadAllowedTypes) {
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
   EXPECT_TRUE(UserMayLoad(nullptr, nullptr, nullptr, nullptr, extension_.get(),
                           nullptr));
 
@@ -1148,23 +1150,23 @@
   EXPECT_TRUE(UserMayLoad(nullptr, nullptr, nullptr, &allowed_types,
                           extension_.get(), nullptr));
 
-  CreateHostedApp(Manifest::INTERNAL);
+  CreateHostedApp(ManifestLocation::kInternal);
   EXPECT_FALSE(UserMayLoad(nullptr, nullptr, nullptr, &allowed_types,
                            extension_.get(), nullptr));
 
-  CreateHostedApp(Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  CreateHostedApp(ManifestLocation::kExternalPolicyDownload);
   EXPECT_FALSE(UserMayLoad(nullptr, nullptr, nullptr, &allowed_types,
                            extension_.get(), nullptr));
 }
 
 TEST_F(ExtensionAdminPolicyTest, UserMayModifySettings) {
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
   EXPECT_TRUE(UserMayModifySettings(extension_.get(), nullptr));
   std::u16string error;
   EXPECT_TRUE(UserMayModifySettings(extension_.get(), &error));
   EXPECT_TRUE(error.empty());
 
-  CreateExtension(Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  CreateExtension(ManifestLocation::kExternalPolicyDownload);
   error.clear();
   EXPECT_FALSE(UserMayModifySettings(extension_.get(), nullptr));
   EXPECT_FALSE(UserMayModifySettings(extension_.get(), &error));
@@ -1172,15 +1174,15 @@
 }
 
 TEST_F(ExtensionAdminPolicyTest, ExtensionMayModifySettings) {
-  CreateExtension(Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  CreateExtension(ManifestLocation::kExternalPolicyDownload);
   auto external_policy_download = extension_;
-  CreateExtension(Manifest::EXTERNAL_POLICY);
+  CreateExtension(ManifestLocation::kExternalPolicy);
   auto external_policy = extension_;
-  CreateExtension(Manifest::EXTERNAL_PREF);
+  CreateExtension(ManifestLocation::kExternalPref);
   auto external_pref = extension_;
-  CreateExtension(Manifest::COMPONENT);
+  CreateExtension(ManifestLocation::kComponent);
   auto component = extension_;
-  CreateExtension(Manifest::COMPONENT);
+  CreateExtension(ManifestLocation::kComponent);
   auto component2 = extension_;
   // Make sure that component/policy/external extensions cannot modify component
   // extensions (no extension may modify a component extension).
@@ -1202,13 +1204,13 @@
 }
 
 TEST_F(ExtensionAdminPolicyTest, MustRemainEnabled) {
-  CreateExtension(Manifest::EXTERNAL_POLICY_DOWNLOAD);
+  CreateExtension(ManifestLocation::kExternalPolicyDownload);
   EXPECT_TRUE(MustRemainEnabled(extension_.get(), nullptr));
   std::u16string error;
   EXPECT_TRUE(MustRemainEnabled(extension_.get(), &error));
   EXPECT_FALSE(error.empty());
 
-  CreateExtension(Manifest::INTERNAL);
+  CreateExtension(ManifestLocation::kInternal);
   error.clear();
   EXPECT_FALSE(MustRemainEnabled(extension_.get(), nullptr));
   EXPECT_FALSE(MustRemainEnabled(extension_.get(), &error));
diff --git a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
index fd7ecf3e..37420e2c 100644
--- a/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
+++ b/chrome/browser/extensions/extension_message_bubble_controller_unittest.cc
@@ -24,7 +24,6 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_web_ui_override_registrar.h"
 #include "chrome/browser/extensions/load_error_reporter.h"
-#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
 #include "chrome/browser/extensions/proxy_overridden_bubble_delegate.h"
 #include "chrome/browser/extensions/settings_api_bubble_delegate.h"
 #include "chrome/browser/extensions/suspicious_extension_bubble_delegate.h"
@@ -994,160 +993,6 @@
   controller.reset();
 }
 
-// The feature this is meant to test is only enacted on Windows, but it should
-// pass on all platforms.
-TEST_F(ExtensionMessageBubbleTest, NtpOverriddenControllerTest) {
-  Init();
-  // Load two extensions overriding new tab page and one overriding something
-  // unrelated (to check for interference). Extension 2 should still win
-  // on the new tab page setting.
-  ASSERT_TRUE(
-      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
-  ASSERT_TRUE(
-      LoadExtensionOverridingNtp("2", kId2, ManifestLocation::kUnpacked));
-  ASSERT_TRUE(
-      LoadExtensionOverridingStart("3", kId3, ManifestLocation::kUnpacked));
-
-  std::unique_ptr<TestExtensionMessageBubbleController> controller(
-      new TestExtensionMessageBubbleController(
-          new NtpOverriddenBubbleDelegate(browser()->profile()), browser()));
-  controller->SetIsActiveBubble();
-
-  // The list will contain one enabled unpacked extension (ext 2).
-  EXPECT_TRUE(controller->ShouldShow());
-  std::vector<std::u16string> override_extensions =
-      controller->GetExtensionList();
-  ASSERT_EQ(1U, override_extensions.size());
-  EXPECT_TRUE(base::ASCIIToUTF16("Extension 2") ==
-              override_extensions[0].c_str());
-  EXPECT_EQ(0U, controller->link_click_count());
-  EXPECT_EQ(0U, controller->dismiss_click_count());
-  EXPECT_EQ(0U, controller->action_click_count());
-
-  // Simulate showing the bubble and dismissing it.
-  FakeExtensionMessageBubble bubble;
-  bubble.set_action_on_show(
-      FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_DISMISS_BUTTON);
-  EXPECT_TRUE(controller->ShouldShow());
-  bubble.set_controller(controller.get());
-  bubble.Show();
-  EXPECT_EQ(0U, controller->link_click_count());
-  EXPECT_EQ(0U, controller->action_click_count());
-  EXPECT_EQ(1U, controller->dismiss_click_count());
-  // No extension should have become disabled.
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL);
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL);
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL);
-  // Only extension 2 should have been acknowledged.
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId1));
-  EXPECT_TRUE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId2));
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId3));
-  // Clean up after ourselves.
-  controller->delegate()->SetBubbleInfoBeenAcknowledged(kId2, false);
-
-  // Simulate clicking the learn more link to dismiss it.
-  bubble.set_action_on_show(
-      FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_LINK);
-  controller.reset(
-      new TestExtensionMessageBubbleController(
-          new NtpOverriddenBubbleDelegate(browser()->profile()),
-          browser()));
-  controller->SetIsActiveBubble();
-  EXPECT_TRUE(controller->ShouldShow());
-  bubble.set_controller(controller.get());
-  bubble.Show();
-  EXPECT_EQ(1U, controller->link_click_count());
-  EXPECT_EQ(0U, controller->action_click_count());
-  EXPECT_EQ(0U, controller->dismiss_click_count());
-  // No extension should have become disabled.
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL);
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2) != NULL);
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL);
-  // Only extension 2 should have been acknowledged.
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId1));
-  EXPECT_TRUE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId2));
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId3));
-  // Clean up after ourselves.
-  controller->delegate()->SetBubbleInfoBeenAcknowledged(kId2, false);
-
-  // Do it again, but now opt to disable the extension.
-  bubble.set_action_on_show(
-      FakeExtensionMessageBubble::BUBBLE_ACTION_CLICK_ACTION_BUTTON);
-  controller.reset(
-      new TestExtensionMessageBubbleController(
-          new NtpOverriddenBubbleDelegate(browser()->profile()),
-          browser()));
-  controller->SetIsActiveBubble();
-  EXPECT_TRUE(controller->ShouldShow());
-  override_extensions = controller->GetExtensionList();
-  EXPECT_EQ(1U, override_extensions.size());
-  bubble.set_controller(controller.get());
-  bubble.Show();  // Simulate showing the bubble.
-  EXPECT_EQ(0U, controller->link_click_count());
-  EXPECT_EQ(1U, controller->action_click_count());
-  EXPECT_EQ(0U, controller->dismiss_click_count());
-  // Only extension 2 should have become disabled.
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1) != NULL);
-  EXPECT_TRUE(registry->disabled_extensions().GetByID(kId2) != NULL);
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3) != NULL);
-  // No extension should have been acknowledged (it got disabled).
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId1));
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId2));
-  EXPECT_FALSE(controller->delegate()->HasBubbleInfoBeenAcknowledged(kId3));
-
-  // Clean up after ourselves.
-  service_->UninstallExtension(kId1,
-                               extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-  service_->UninstallExtension(kId2,
-                               extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-  service_->UninstallExtension(kId3,
-                               extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-}
-
-// Tests that the NTP override bubble is shown (on the new tab page) each time
-// an NTP overriding extension is installed for a single profile. Note that the
-// NTP bubble is only implemented on Windows and ChromeOs, but this test should
-// still pass on Linux and Mac.
-TEST_F(ExtensionMessageBubbleTest, ShowNtpBubblePerProfilePerExtensionTest) {
-  Init();
-  ASSERT_TRUE(
-      LoadExtensionOverridingNtp("1", kId1, ManifestLocation::kUnpacked));
-  std::unique_ptr<TestExtensionMessageBubbleController> controller(
-      std::make_unique<TestExtensionMessageBubbleController>(
-          new NtpOverriddenBubbleDelegate(browser()->profile()), browser()));
-  ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 1");
-
-  ASSERT_TRUE(
-      LoadExtensionOverridingNtp("2", kId2, ManifestLocation::kUnpacked));
-  controller = std::make_unique<TestExtensionMessageBubbleController>(
-      new NtpOverriddenBubbleDelegate(browser()->profile()), browser());
-  ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 2");
-
-  ASSERT_TRUE(
-      LoadExtensionOverridingNtp("3", kId3, ManifestLocation::kUnpacked));
-  controller = std::make_unique<TestExtensionMessageBubbleController>(
-      new NtpOverriddenBubbleDelegate(browser()->profile()), browser());
-  ShowAndDismissBubbleByDeactivation(controller.get(), "Extension 3");
-
-  // No extension should have become disabled.
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId1));
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId2));
-  EXPECT_TRUE(registry->enabled_extensions().GetByID(kId3));
-
-  // Clean up after ourselves.
-  service_->UninstallExtension(kId1, extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-  service_->UninstallExtension(kId2, extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-  service_->UninstallExtension(kId3, extensions::UNINSTALL_REASON_FOR_TESTING,
-                               NULL);
-}
-
 void SetInstallTime(const std::string& extension_id,
                     const base::Time& time,
                     ExtensionPrefs* prefs) {
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 781e780..7f050fab 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -38,6 +38,7 @@
 
 using base::Time;
 using base::TimeDelta;
+using extensions::mojom::ManifestLocation;
 
 namespace extensions {
 
@@ -486,8 +487,9 @@
     base::FilePath path =
         prefs_.extensions_dir().AppendASCII(base::NumberToString(num));
     std::string errors;
-    scoped_refptr<Extension> extension = Extension::Create(
-        path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id, &errors);
+    scoped_refptr<Extension> extension =
+        Extension::Create(path, ManifestLocation::kInternal, manifest,
+                          Extension::NO_FLAGS, id, &errors);
     ASSERT_TRUE(extension.get()) << errors;
     ASSERT_EQ(id, extension->id());
     prefs()->SetDelayedInstallInfo(extension.get(),
@@ -613,8 +615,9 @@
     base::FilePath path =
         prefs_.extensions_dir().AppendASCII("test_0.2");
     std::string errors;
-    scoped_refptr<Extension> new_extension = Extension::Create(
-        path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, id_, &errors);
+    scoped_refptr<Extension> new_extension =
+        Extension::Create(path, ManifestLocation::kInternal, manifest,
+                          Extension::NO_FLAGS, id_, &errors);
     ASSERT_TRUE(new_extension.get()) << errors;
     ASSERT_EQ(id_, new_extension->id());
     prefs()->SetDelayedInstallInfo(new_extension.get(),
@@ -743,34 +746,22 @@
   simple_dict.SetInteger(manifest_keys::kManifestVersion, 2);
   simple_dict.SetString(manifest_keys::kName, "unused");
 
-  extension1_ = Extension::Create(
-      prefs_.temp_dir().AppendASCII("ext1_"),
-      Manifest::EXTERNAL_PREF,
-      simple_dict,
-      Extension::NO_FLAGS,
-      &error);
-  extension2_ = Extension::Create(
-      prefs_.temp_dir().AppendASCII("ext2_"),
-      Manifest::EXTERNAL_PREF,
-      simple_dict,
-      Extension::NO_FLAGS,
-      &error);
-  extension3_ = Extension::Create(
-      prefs_.temp_dir().AppendASCII("ext3_"),
-      Manifest::EXTERNAL_PREF,
-      simple_dict,
-      Extension::NO_FLAGS,
-      &error);
-  extension4_ = Extension::Create(
-      prefs_.temp_dir().AppendASCII("ext4_"),
-      Manifest::EXTERNAL_PREF,
-      simple_dict,
-      Extension::NO_FLAGS,
-      &error);
+  extension1_ = Extension::Create(prefs_.temp_dir().AppendASCII("ext1_"),
+                                  ManifestLocation::kExternalPref, simple_dict,
+                                  Extension::NO_FLAGS, &error);
+  extension2_ = Extension::Create(prefs_.temp_dir().AppendASCII("ext2_"),
+                                  ManifestLocation::kExternalPref, simple_dict,
+                                  Extension::NO_FLAGS, &error);
+  extension3_ = Extension::Create(prefs_.temp_dir().AppendASCII("ext3_"),
+                                  ManifestLocation::kExternalPref, simple_dict,
+                                  Extension::NO_FLAGS, &error);
+  extension4_ = Extension::Create(prefs_.temp_dir().AppendASCII("ext4_"),
+                                  ManifestLocation::kExternalPref, simple_dict,
+                                  Extension::NO_FLAGS, &error);
 
   internal_extension_ = Extension::Create(
-      prefs_.temp_dir().AppendASCII("internal extension"), Manifest::INTERNAL,
-      simple_dict, Extension::NO_FLAGS, &error);
+      prefs_.temp_dir().AppendASCII("internal extension"),
+      ManifestLocation::kInternal, simple_dict, Extension::NO_FLAGS, &error);
 
   for (size_t i = 0; i < kNumInstalledExtensions; ++i)
     installed_[i] = false;
@@ -945,7 +936,7 @@
     // Adding a component extension.
     component_extension_ =
         ExtensionBuilder("a")
-            .SetLocation(mojom::ManifestLocation::kComponent)
+            .SetLocation(ManifestLocation::kComponent)
             .SetPath(prefs_.extensions_dir().AppendASCII("a"))
             .Build();
     prefs_.AddExtension(component_extension_.get());
@@ -953,7 +944,7 @@
     // Adding a non component extension.
     no_component_extension_ =
         ExtensionBuilder("b")
-            .SetLocation(mojom::ManifestLocation::kInternal)
+            .SetLocation(ManifestLocation::kInternal)
             .SetPath(prefs_.extensions_dir().AppendASCII("b"))
             .Build();
     prefs_.AddExtension(no_component_extension_.get());
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index fcc4c97..05b6bc09 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -98,8 +98,8 @@
 
   std::string error;
   scoped_refptr<Extension> extension(
-      Extension::Create(path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS,
-                        extension_id, &error));
+      Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
+                        Extension::NO_FLAGS, extension_id, &error));
   EXPECT_TRUE(extension.get()) << error;
   return extension;
 }
@@ -126,8 +126,9 @@
   path = path.AppendASCII("web_store");
 
   std::string error;
-  scoped_refptr<Extension> extension(Extension::Create(
-      path, Manifest::COMPONENT, *manifest, Extension::NO_FLAGS, &error));
+  scoped_refptr<Extension> extension(
+      Extension::Create(path, mojom::ManifestLocation::kComponent, *manifest,
+                        Extension::NO_FLAGS, &error));
   EXPECT_TRUE(extension.get()) << error;
   return extension;
 }
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 94cf9a1..444c38b 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -569,7 +569,8 @@
     if (info->extension_manifest) {
       std::string error;
       extension = Extension::Create(
-          info->extension_path, info->extension_location,
+          info->extension_path,
+          static_cast<mojom::ManifestLocation>(info->extension_location),
           *info->extension_manifest,
           extension_prefs_->GetDelayedInstallCreationFlags(info->extension_id),
           info->extension_id, &error);
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc
index 86af4401..9c69da29 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.cc
+++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -422,6 +422,11 @@
   // did so a bunch of stuff fails. Migrate this over.
   extension_loader.set_ignore_manifest_warnings(true);
   extension_loader.LoadExtension(crx_path);
+
+  // Make sure RegisterClient calls for storage are finished to avoid flaky
+  // crashes in QuotaManagerImpl::RegisterClient on test shutdown.
+  // TODO(crbug.com/1182630) : Remove this when 1182630 is fixed.
+  base::RunLoop().RunUntilIdle();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
index c5c8bdc..5428fa7 100644
--- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -28,6 +28,7 @@
 using extensions::Extension;
 using extensions::ExtensionSet;
 using extensions::Manifest;
+using extensions::mojom::ManifestLocation;
 using storage::SpecialStoragePolicy;
 
 typedef SpecialStoragePolicy::StoragePolicy StoragePolicy;
@@ -115,9 +116,9 @@
     list->AppendString("*://*.wildcards/protected");
     manifest.Set(keys::kWebURLs, std::move(list));
     std::string error;
-    scoped_refptr<Extension> protected_app = Extension::Create(
-        path, Manifest::INVALID_LOCATION, manifest,
-        Extension::NO_FLAGS, &error);
+    scoped_refptr<Extension> protected_app =
+        Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
+                          Extension::NO_FLAGS, &error);
     EXPECT_TRUE(protected_app.get()) << error;
     return protected_app;
   }
@@ -140,9 +141,9 @@
     list->AppendString("*://*.wildcards/unlimited");
     manifest.Set(keys::kWebURLs, std::move(list));
     std::string error;
-    scoped_refptr<Extension> unlimited_app = Extension::Create(
-        path, Manifest::INVALID_LOCATION, manifest,
-        Extension::NO_FLAGS, &error);
+    scoped_refptr<Extension> unlimited_app =
+        Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
+                          Extension::NO_FLAGS, &error);
     EXPECT_TRUE(unlimited_app.get()) << error;
     return unlimited_app;
   }
@@ -158,9 +159,9 @@
     manifest.SetString(keys::kVersion, "1");
     manifest.SetString(keys::kPlatformAppBackgroundPage, "background.html");
     std::string error;
-    scoped_refptr<Extension> app = Extension::Create(
-        path, Manifest::INVALID_LOCATION, manifest,
-        Extension::NO_FLAGS, &error);
+    scoped_refptr<Extension> app =
+        Extension::Create(path, ManifestLocation::kInvalidLocation, manifest,
+                          Extension::NO_FLAGS, &error);
     EXPECT_TRUE(app.get()) << error;
     return app;
   }
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index 46f05ce..baf84476 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -191,10 +191,8 @@
   if (info.extension_manifest) {
     extension = Extension::Create(
         info.extension_path,
-        info.extension_location,
-        *info.extension_manifest,
-        GetCreationFlags(&info),
-        &error);
+        static_cast<mojom::ManifestLocation>(info.extension_location),
+        *info.extension_manifest, GetCreationFlags(&info), &error);
   } else {
     error = manifest_errors::kManifestUnreadable;
   }
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_delegate.cc b/chrome/browser/extensions/ntp_overridden_bubble_delegate.cc
deleted file mode 100644
index 3ef616cc..0000000
--- a/chrome/browser/extensions/ntp_overridden_bubble_delegate.cc
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright (c) 2014 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/extensions/ntp_overridden_bubble_delegate.h"
-
-#include <memory>
-
-#include "base/metrics/histogram_macros.h"
-#include "build/build_config.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_web_ui.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/prefs/pref_registry.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/extension_system.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace {
-
-// Whether existing NTP extensions have been automatically acknowledged.
-const char kDidAcknowledgeExistingNtpExtensions[] =
-    "ack_existing_ntp_extensions";
-
-// Whether to acknowledge existing extensions overriding the NTP for the active
-// profile. Active on MacOS to rollout the NTP bubble without prompting for
-// previously-installed extensions.
-bool g_acknowledge_existing_extensions =
-#if defined(OS_MAC)
-    true;
-#else
-    false;
-#endif
-
-base::LazyInstance<std::set<std::pair<Profile*, std::string>>>::Leaky
-    g_ntp_overridden_shown = LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-namespace extensions {
-
-const char NtpOverriddenBubbleDelegate::kNtpBubbleAcknowledged[] =
-    "ack_ntp_bubble";
-
-NtpOverriddenBubbleDelegate::NtpOverriddenBubbleDelegate(Profile* profile)
-    : extensions::ExtensionMessageBubbleController::Delegate(profile),
-      profile_(profile) {
-  set_acknowledged_flag_pref_name(kNtpBubbleAcknowledged);
-}
-
-NtpOverriddenBubbleDelegate::~NtpOverriddenBubbleDelegate() {}
-
-// static
-void NtpOverriddenBubbleDelegate::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterBooleanPref(kDidAcknowledgeExistingNtpExtensions, false,
-                                PrefRegistry::NO_REGISTRATION_FLAGS);
-}
-
-// static
-void NtpOverriddenBubbleDelegate::MaybeAcknowledgeExistingNtpExtensions(
-    Profile* profile) {
-  if (!g_acknowledge_existing_extensions)
-    return;
-
-  ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
-  PrefService* profile_prefs = profile->GetPrefs();
-  // Only acknowledge existing extensions once per profile.
-  if (profile_prefs->GetBoolean(kDidAcknowledgeExistingNtpExtensions))
-    return;
-
-  profile_prefs->SetBoolean(kDidAcknowledgeExistingNtpExtensions, true);
-  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile);
-  for (const auto& extension : registry->enabled_extensions()) {
-    const URLOverrides::URLOverrideMap& overrides =
-        URLOverrides::GetChromeURLOverrides(extension.get());
-    if (overrides.find(chrome::kChromeUINewTabHost) != overrides.end()) {
-      prefs->UpdateExtensionPref(extension->id(), kNtpBubbleAcknowledged,
-                                 std::make_unique<base::Value>(true));
-    }
-  }
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldIncludeExtension(
-    const extensions::Extension* extension) {
-  if (!extension_id_.empty() && extension_id_ != extension->id())
-    return false;
-
-  GURL url(chrome::kChromeUINewTabURL);
-  if (!ExtensionWebUI::HandleChromeURLOverride(&url, profile()))
-    return false;  // No override for newtab found.
-
-  if (extension->id() != url.host_piece())
-    return false;
-
-  if (HasBubbleInfoBeenAcknowledged(extension->id()))
-    return false;
-
-  extension_id_ = extension->id();
-  return true;
-}
-
-void NtpOverriddenBubbleDelegate::AcknowledgeExtension(
-    const std::string& extension_id,
-    ExtensionMessageBubbleController::BubbleAction user_action) {
-  if (user_action != ExtensionMessageBubbleController::ACTION_EXECUTE)
-    SetBubbleInfoBeenAcknowledged(extension_id, true);
-}
-
-void NtpOverriddenBubbleDelegate::PerformAction(
-    const extensions::ExtensionIdList& list) {
-  for (size_t i = 0; i < list.size(); ++i) {
-    service()->DisableExtension(
-        list[i], extensions::disable_reason::DISABLE_USER_ACTION);
-  }
-}
-
-std::u16string NtpOverriddenBubbleDelegate::GetTitle() const {
-  return l10n_util::GetStringUTF16(
-      IDS_EXTENSIONS_NTP_CONTROLLED_TITLE_HOME_PAGE_BUBBLE);
-}
-
-std::u16string NtpOverriddenBubbleDelegate::GetMessageBody(
-    bool anchored_to_browser_action,
-    int extension_count) const {
-  std::u16string body =
-      l10n_util::GetStringUTF16(IDS_EXTENSIONS_NTP_CONTROLLED_FIRST_LINE);
-  body += l10n_util::GetStringUTF16(
-      IDS_EXTENSIONS_SETTINGS_API_THIRD_LINE_CONFIRMATION);
-  return body;
-}
-
-std::u16string NtpOverriddenBubbleDelegate::GetOverflowText(
-    const std::u16string& overflow_count) const {
-  // Does not have more than one extension in the list at a time.
-  NOTREACHED();
-  return std::u16string();
-}
-
-GURL NtpOverriddenBubbleDelegate::GetLearnMoreUrl() const {
-  return GURL(chrome::kExtensionControlledSettingLearnMoreURL);
-}
-
-std::u16string NtpOverriddenBubbleDelegate::GetActionButtonLabel() const {
-  return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_RESTORE_SETTINGS);
-}
-
-std::u16string NtpOverriddenBubbleDelegate::GetDismissButtonLabel() const {
-  return l10n_util::GetStringUTF16(IDS_EXTENSION_CONTROLLED_KEEP_CHANGES);
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldCloseOnDeactivate() const {
-  return true;
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldShowExtensionList() const {
-  return false;
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldHighlightExtensions() const {
-  return false;
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldLimitToEnabledExtensions() const {
-  return true;
-}
-
-bool NtpOverriddenBubbleDelegate::ShouldShow(
-    const ExtensionIdList& extensions) const {
-  DCHECK_EQ(1u, extensions.size());
-  return !g_ntp_overridden_shown.Get().count(
-      std::make_pair(profile_, extensions[0]));
-}
-
-void NtpOverriddenBubbleDelegate::OnShown(const ExtensionIdList& extensions) {
-  DCHECK_EQ(1u, extensions.size());
-  DCHECK(!g_ntp_overridden_shown.Get().count(
-      std::make_pair(profile_, extensions[0])));
-  g_ntp_overridden_shown.Get().insert(std::make_pair(profile_, extensions[0]));
-}
-
-void NtpOverriddenBubbleDelegate::OnAction() {
-  // We clear the profile set because the user chooses to remove or disable the
-  // extension. Thus if that extension or another takes effect, it is worth
-  // mentioning to the user (ShouldShow() would return true) because it is
-  // contrary to the user's choice.
-  g_ntp_overridden_shown.Get().clear();
-}
-
-void NtpOverriddenBubbleDelegate::ClearProfileSetForTesting() {
-  g_ntp_overridden_shown.Get().clear();
-}
-
-void NtpOverriddenBubbleDelegate::LogExtensionCount(size_t count) {
-}
-
-void NtpOverriddenBubbleDelegate::LogAction(
-    ExtensionMessageBubbleController::BubbleAction action) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "ExtensionOverrideBubble.NtpOverriddenUserSelection",
-      action,
-      ExtensionMessageBubbleController::ACTION_BOUNDARY);
-}
-
-bool NtpOverriddenBubbleDelegate::SupportsPolicyIndicator() {
-  return true;
-}
-
-void NtpOverriddenBubbleDelegate::
-    set_acknowledge_existing_extensions_for_testing(
-        bool acknowledge_existing_extensions) {
-  g_acknowledge_existing_extensions = acknowledge_existing_extensions;
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_delegate.h b/chrome/browser/extensions/ntp_overridden_bubble_delegate.h
deleted file mode 100644
index f27b155..0000000
--- a/chrome/browser/extensions/ntp_overridden_bubble_delegate.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2014 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_EXTENSIONS_NTP_OVERRIDDEN_BUBBLE_DELEGATE_H_
-#define CHROME_BROWSER_EXTENSIONS_NTP_OVERRIDDEN_BUBBLE_DELEGATE_H_
-
-#include <stddef.h>
-
-#include <string>
-
-#include "base/macros.h"
-#include "chrome/browser/extensions/extension_message_bubble_controller.h"
-
-class PrefRegistrySimple;
-
-namespace extensions {
-
-class NtpOverriddenBubbleDelegate
-    : public ExtensionMessageBubbleController::Delegate {
- public:
-  // Name of the preference that says whether the user has been notified about
-  // extension overriding the new tab page.
-  static const char kNtpBubbleAcknowledged[];
-
-  explicit NtpOverriddenBubbleDelegate(Profile* profile);
-  ~NtpOverriddenBubbleDelegate() override;
-
-  // Registers associated preferences.
-  static void RegisterPrefs(PrefRegistrySimple* registry);
-
-  // Iterates over existing NTP-overriding extensions installed in the given
-  // |profile| and marks them as acknowledged. Stores a preference indicating
-  // the action was completed. Subsequent calls will *not* acknowledge more
-  // extensions. This is needed to avoid prompting users with existing
-  // extensions when we expand the warning to new platforms.
-  // TODO(devlin): Remove this in M62.
-  static void MaybeAcknowledgeExistingNtpExtensions(Profile* profile);
-
-  // ExtensionMessageBubbleController::Delegate methods.
-  bool ShouldIncludeExtension(const extensions::Extension* extension) override;
-  void AcknowledgeExtension(
-      const std::string& extension_id,
-      extensions::ExtensionMessageBubbleController::BubbleAction user_action)
-      override;
-  void PerformAction(const extensions::ExtensionIdList& list) override;
-  std::u16string GetTitle() const override;
-  std::u16string GetMessageBody(bool anchored_to_browser_action,
-                                int extension_count) const override;
-  std::u16string GetOverflowText(
-      const std::u16string& overflow_count) const override;
-  GURL GetLearnMoreUrl() const override;
-  std::u16string GetActionButtonLabel() const override;
-  std::u16string GetDismissButtonLabel() const override;
-  bool ShouldCloseOnDeactivate() const override;
-  bool ShouldShow(const ExtensionIdList& extensions) const override;
-  void OnShown(const ExtensionIdList& extensions) override;
-  void OnAction() override;
-  void ClearProfileSetForTesting() override;
-  bool ShouldShowExtensionList() const override;
-  bool ShouldHighlightExtensions() const override;
-  bool ShouldLimitToEnabledExtensions() const override;
-  void LogExtensionCount(size_t count) override;
-  void LogAction(ExtensionMessageBubbleController::BubbleAction) override;
-  bool SupportsPolicyIndicator() override;
-
-  static void set_acknowledge_existing_extensions_for_testing(
-      bool acknowledge_existing_extensions);
-
- private:
-  Profile* profile_;
-
-  // The ID of the extension we are showing the bubble for.
-  std::string extension_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(NtpOverriddenBubbleDelegate);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_EXTENSIONS_NTP_OVERRIDDEN_BUBBLE_DELEGATE_H_
diff --git a/chrome/browser/extensions/omnibox_focus_interactive_test.cc b/chrome/browser/extensions/omnibox_focus_interactive_test.cc
index dcf4b861..da29414 100644
--- a/chrome/browser/extensions/omnibox_focus_interactive_test.cc
+++ b/chrome/browser/extensions/omnibox_focus_interactive_test.cc
@@ -6,8 +6,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
-#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
 #include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -51,9 +51,9 @@
     // Prevent a focus-stealing focus bubble that warns the user that "An
     // extension has changed what page is shown when you open a new tab."
     ExtensionPrefs* prefs = ExtensionPrefs::Get(browser()->profile());
-    prefs->UpdateExtensionPref(
-        extension->id(), NtpOverriddenBubbleDelegate::kNtpBubbleAcknowledged,
-        std::make_unique<base::Value>(true));
+    prefs->UpdateExtensionPref(extension->id(),
+                               kNtpOverridingExtensionAcknowledged,
+                               std::make_unique<base::Value>(true));
 
     return extension;
   }
diff --git a/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc b/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
index 64e3b1e..dd3daa8b 100644
--- a/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
+++ b/chrome/browser/extensions/permissions_based_management_policy_provider_unittest.cc
@@ -73,7 +73,8 @@
     }
     std::string error;
     scoped_refptr<const Extension> extension = Extension::Create(
-        base::FilePath(), location, manifest_dict, Extension::NO_FLAGS, &error);
+        base::FilePath(), static_cast<mojom::ManifestLocation>(location),
+        manifest_dict, Extension::NO_FLAGS, &error);
     CHECK(extension.get()) << error;
     return extension;
   }
diff --git a/chrome/browser/extensions/test_extension_prefs.cc b/chrome/browser/extensions/test_extension_prefs.cc
index 5712635..3b59643a 100644
--- a/chrome/browser/extensions/test_extension_prefs.cc
+++ b/chrome/browser/extensions/test_extension_prefs.cc
@@ -171,8 +171,9 @@
   EXPECT_TRUE(manifest.GetString(manifest_keys::kName, &name));
   base::FilePath path =  extensions_dir_.AppendASCII(name);
   std::string errors;
-  scoped_refptr<Extension> extension = Extension::Create(
-      path, location, manifest, extra_flags, &errors);
+  scoped_refptr<Extension> extension =
+      Extension::Create(path, static_cast<mojom::ManifestLocation>(location),
+                        manifest, extra_flags, &errors);
   EXPECT_TRUE(extension.get()) << errors;
   if (!extension.get())
     return nullptr;
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 6fc5192..320f6f94 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -67,8 +67,8 @@
   std::unique_ptr<base::DictionaryValue> value = LoadManifestFile(path, error);
   if (!value)
     return nullptr;
-  return Extension::Create(path.DirName(), Manifest::UNPACKED, *value,
-                           Extension::NO_FLAGS, error);
+  return Extension::Create(path.DirName(), mojom::ManifestLocation::kUnpacked,
+                           *value, Extension::NO_FLAGS, error);
 }
 
 }  // namespace
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index b72095a0..c041884 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -831,11 +831,6 @@
     "expiry_milestone": 92
   },
   {
-    "name": "crostini-webui-upgrader",
-    "owners": [ "nverne", "davidmunro@google.com", "benwells" ],
-    "expiry_milestone": 88
-  },
-  {
     "name": "cryptauth-v2-device-activity-status",
     "owners": [ "khorimoto", "nohle", "themaxli" ],
     "expiry_milestone": 93
@@ -1443,11 +1438,6 @@
     "expiry_milestone": 90
   },
   {
-    "name": "enable-bluetooth-verbose-logs-for-googlers",
-    "owners": [ "sonnysasaka" ],
-    "expiry_milestone": 90
-  },
-  {
     "name": "enable-browsing-data-lifetime-manager",
     "owners": ["ydago"],
     "expiry_milestone": 91
@@ -2251,7 +2241,7 @@
   {
     "name": "enable-reader-mode",
     "owners": [ "katie", "dmazzoni" ],
-    "expiry_milestone": 90
+    "expiry_milestone": 95
   },
   {
     "name": "enable-reader-mode-in-cct",
@@ -2804,11 +2794,6 @@
     "expiry_milestone": 90
   },
   {
-    "name": "files-camera-folder",
-    "owners": [ "wtlee", "chromeos-camera-eng@google.com" ],
-    "expiry_milestone": 90
-  },
-  {
     "name": "files-filters-in-recents",
     "owners": [ "fukino", "weifangsun" ],
     "expiry_milestone": 90
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 208018d..b249c5e 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3959,10 +3959,6 @@
 const char kCrostiniGpuSupportName[] = "Crostini GPU Support";
 const char kCrostiniGpuSupportDescription[] = "Enable Crostini GPU support.";
 
-const char kCrostiniWebUIUpgraderName[] = "Crostini WebUI Upgrader";
-const char kCrostiniWebUIUpgraderDescription[] =
-    "Enable the new WebUI Crostini Upgrader Dialog.";
-
 const char kCrostiniUseDlcName[] = "Crostini Use DLC";
 const char kCrostiniUseDlcDescription[] =
     "Download the termina VM using the new DLC service instead of the old "
@@ -4370,12 +4366,6 @@
 const char kFilesAppCopyImageDescription[] =
     "Enables the Files App to copy images selected to the system clipboard";
 
-const char kFilesCameraFolderName[] =
-    "Enable Camera folder handling in Files App";
-const char kFilesCameraFolderDescription[] =
-    "Enables the Files App to display Camera folder with i18n name and make it "
-    "nonmodifiable";
-
 const char kFilesJsModulesName[] = "Enable JS Modules for Files app";
 const char kFilesJsModulesDescription[] =
     "Enable running Files app using JS Modules.";
@@ -4694,11 +4684,6 @@
     "Enables a toggle which can enable debug (i.e., verbose) logs for "
     "Bluetooth";
 
-const char kEnableBluetoothVerboseLogsForGooglersName[] =
-    "Enable Bluetooth verbose logs for Googlers";
-const char kEnableBluetoothVerboseLogsForGooglersDescription[] =
-    "Enables Bluetooth verbose logs for Googlers in feedback reports.";
-
 const char kBluetoothSessionizedMetricsName[] =
     "Enable Bluetooth sessionized metrics";
 const char kBluetoothSessionizedMetricsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 26360f2..86081eb 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2301,9 +2301,6 @@
 extern const char kCrostiniGpuSupportName[];
 extern const char kCrostiniGpuSupportDescription[];
 
-extern const char kCrostiniWebUIUpgraderName[];
-extern const char kCrostiniWebUIUpgraderDescription[];
-
 extern const char kCrostiniUseDlcName[];
 extern const char kCrostiniUseDlcDescription[];
 
@@ -2568,9 +2565,6 @@
 extern const char kFilesAppCopyImageName[];
 extern const char kFilesAppCopyImageDescription[];
 
-extern const char kFilesCameraFolderName[];
-extern const char kFilesCameraFolderDescription[];
-
 extern const char kFilesNGName[];
 extern const char kFilesNGDescription[];
 
@@ -2762,9 +2756,6 @@
 extern const char kShowBluetoothDebugLogToggleName[];
 extern const char kShowBluetoothDebugLogToggleDescription[];
 
-extern const char kEnableBluetoothVerboseLogsForGooglersName[];
-extern const char kEnableBluetoothVerboseLogsForGooglersDescription[];
-
 extern const char kBluetoothSessionizedMetricsName[];
 extern const char kBluetoothSessionizedMetricsDescription[];
 
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index 963b70a..238a547 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -67,9 +67,9 @@
   base::FilePath path = extension_prefs->install_directory().AppendASCII(name);
   std::string errors;
   scoped_refptr<extensions::Extension> extension =
-      extensions::Extension::Create(path, extensions::Manifest::INTERNAL,
-                                    *manifest.get(),
-                                    extensions::Extension::NO_FLAGS, &errors);
+      extensions::Extension::Create(
+          path, extensions::mojom::ManifestLocation::kInternal, *manifest.get(),
+          extensions::Extension::NO_FLAGS, &errors);
   EXPECT_TRUE(extension.get() != nullptr) << errors;
   EXPECT_TRUE(crx_file::id_util::IdIsValid(extension->id()));
   if (!extension.get() || !crx_file::id_util::IdIsValid(extension->id()))
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
index 37ce8f6..9fb435a 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer_unittest.cc
@@ -81,7 +81,7 @@
   scoped_refptr<extensions::Extension> extension =
       extensions::Extension::Create(
           base::FilePath(FILE_PATH_LITERAL("//no-such-file")),
-          extensions::Manifest::INVALID_LOCATION, manifest,
+          extensions::mojom::ManifestLocation::kInvalidLocation, manifest,
           extensions::Extension::NO_FLAGS, "mbflcebpggnecokmikipoihdbecnjfoj",
           &error);
   ASSERT_TRUE(error.empty());
diff --git a/chrome/browser/platform_util_unittest.cc b/chrome/browser/platform_util_unittest.cc
index ecd0bc1..4c32fe4d 100644
--- a/chrome/browser/platform_util_unittest.cc
+++ b/chrome/browser/platform_util_unittest.cc
@@ -115,8 +115,8 @@
     scoped_refptr<extensions::Extension> extension =
         extensions::Extension::Create(
             test_directory.AppendASCII("invalid-extension"),
-            extensions::Manifest::INVALID_LOCATION, *manifest_dictionary,
-            extensions::Extension::NO_FLAGS, &error);
+            extensions::mojom::ManifestLocation::kInvalidLocation,
+            *manifest_dictionary, extensions::Extension::NO_FLAGS, &error);
     ASSERT_TRUE(error.empty()) << error;
     extensions::ExtensionRegistry::Get(GetProfile())->AddEnabled(extension);
   }
diff --git a/chrome/browser/portal/portal_browsertest.cc b/chrome/browser/portal/portal_browsertest.cc
index 412b1d1d..c0724ff5 100644
--- a/chrome/browser/portal/portal_browsertest.cc
+++ b/chrome/browser/portal/portal_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_test_utils.h"
@@ -90,8 +91,16 @@
   EXPECT_EQ(portal_contents, tab_strip_model->GetActiveWebContents());
 }
 
+// Flaky on Linux ASAN. crbug.com/1182702
+#if defined(ADDRESS_SANITIZER) && defined(OS_LINUX)
+#define MAYBE_DevToolsWindowStaysOpenAfterActivation \
+  DISABLED_DevToolsWindowStaysOpenAfterActivation
+#else
+#define MAYBE_DevToolsWindowStaysOpenAfterActivation \
+  DevToolsWindowStaysOpenAfterActivation
+#endif
 IN_PROC_BROWSER_TEST_F(PortalBrowserTest,
-                       DevToolsWindowStaysOpenAfterActivation) {
+                       MAYBE_DevToolsWindowStaysOpenAfterActivation) {
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL url(embedded_test_server()->GetURL("/portal/activate.html"));
   ui_test_utils::NavigateToURL(browser(), url);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 7d0de78..8539c00 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -168,7 +168,7 @@
 #include "chrome/browser/extensions/api/tabs/tabs_api.h"
 #include "chrome/browser/extensions/default_apps.h"
 #include "chrome/browser/extensions/extension_web_ui.h"
-#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
+#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h"
 #include "chrome/browser/ui/webui/extensions/extensions_ui.h"
 #include "extensions/browser/api/audio/audio_api.h"
@@ -978,8 +978,11 @@
   extensions::AudioAPI::RegisterUserPrefs(registry);
   extensions::ExtensionPrefs::RegisterProfilePrefs(registry);
   extensions::ExtensionsUI::RegisterProfilePrefs(registry);
-  extensions::NtpOverriddenBubbleDelegate::RegisterPrefs(registry);
   extensions::RuntimeAPI::RegisterPrefs(registry);
+  // TODO(devlin): This would be more inline with the other calls here if it
+  // were nested in either a class or separate namespace with a simple
+  // Register[Profile]Prefs() name.
+  extensions::RegisterSettingsOverriddenUiPrefs(registry);
   update_client::RegisterProfilePrefs(registry);
   web_app::WebAppProvider::RegisterProfilePrefs(registry);
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 8204a9cb..09c9712 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -68,6 +68,7 @@
 #include "base/win/shortcut.h"
 #endif
 
+using extensions::mojom::ManifestLocation;
 
 namespace {
 
@@ -349,7 +350,7 @@
 
 scoped_refptr<Extension> CreateExtension(const std::u16string& name,
                                          const base::FilePath& path,
-                                         Manifest::Location location,
+                                         ManifestLocation location,
                                          extensions::Manifest::Type type,
                                          bool installed_by_default) {
   base::DictionaryValue manifest;
@@ -533,8 +534,8 @@
   test::ThemeServiceChangedWaiter waiter(theme_service);
 
   scoped_refptr<Extension> theme = CreateExtension(
-      base::ASCIIToUTF16("example1"), temp_dir.GetPath(), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_THEME, false);
+      base::ASCIIToUTF16("example1"), temp_dir.GetPath(),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_THEME, false);
   service_->FinishInstallationForTest(theme.get());
   waiter.WaitForThemeChanged();
 
@@ -542,37 +543,33 @@
 
   scoped_refptr<Extension> ext2 = CreateExtension(
       base::ASCIIToUTF16("example2"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext2.get());
   // Component extensions and policy-managed extensions shouldn't be disabled.
-  scoped_refptr<Extension> ext3 = CreateExtension(
-      base::ASCIIToUTF16("example3"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")),
-      Manifest::COMPONENT,
-      extensions::Manifest::TYPE_EXTENSION,
-      false);
+  scoped_refptr<Extension> ext3 =
+      CreateExtension(base::ASCIIToUTF16("example3"),
+                      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")),
+                      ManifestLocation::kComponent,
+                      extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext3.get());
   scoped_refptr<Extension> ext4 =
       CreateExtension(base::ASCIIToUTF16("example4"),
                       base::FilePath(FILE_PATH_LITERAL("//nonexistent3")),
-                      Manifest::EXTERNAL_POLICY_DOWNLOAD,
-                      extensions::Manifest::TYPE_EXTENSION,
-                      false);
+                      ManifestLocation::kExternalPolicyDownload,
+                      extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext4.get());
-  scoped_refptr<Extension> ext5 = CreateExtension(
-      base::ASCIIToUTF16("example5"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent4")),
-      Manifest::EXTERNAL_COMPONENT,
-      extensions::Manifest::TYPE_EXTENSION,
-      false);
+  scoped_refptr<Extension> ext5 =
+      CreateExtension(base::ASCIIToUTF16("example5"),
+                      base::FilePath(FILE_PATH_LITERAL("//nonexistent4")),
+                      ManifestLocation::kExternalComponent,
+                      extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext5.get());
-  scoped_refptr<Extension> ext6 = CreateExtension(
-      base::ASCIIToUTF16("example6"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent5")),
-      Manifest::EXTERNAL_POLICY,
-      extensions::Manifest::TYPE_EXTENSION,
-      false);
+  scoped_refptr<Extension> ext6 =
+      CreateExtension(base::ASCIIToUTF16("example6"),
+                      base::FilePath(FILE_PATH_LITERAL("//nonexistent5")),
+                      ManifestLocation::kExternalPolicy,
+                      extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext6.get());
   EXPECT_EQ(6u, registry()->enabled_extensions().size());
 
@@ -590,14 +587,14 @@
 TEST_F(ProfileResetterTest, ResetExtensionsByDisablingNonOrganic) {
   scoped_refptr<Extension> ext2 = CreateExtension(
       base::ASCIIToUTF16("example2"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext2.get());
   // Components and external policy extensions shouldn't be deleted.
   scoped_refptr<Extension> ext3 = CreateExtension(
       base::ASCIIToUTF16("example3"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext3.get());
   EXPECT_EQ(2u, registry()->enabled_extensions().size());
 
@@ -620,8 +617,8 @@
   test::ThemeServiceChangedWaiter waiter(theme_service);
 
   scoped_refptr<Extension> ext1 = CreateExtension(
-      base::ASCIIToUTF16("example1"), temp_dir.GetPath(), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_THEME, false);
+      base::ASCIIToUTF16("example1"), temp_dir.GetPath(),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_THEME, false);
   service_->FinishInstallationForTest(ext1.get());
   waiter.WaitForThemeChanged();
 
@@ -629,14 +626,14 @@
 
   scoped_refptr<Extension> ext2 = CreateExtension(
       base::ASCIIToUTF16("example2"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent2")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext2.get());
 
   scoped_refptr<Extension> ext3 = CreateExtension(
       base::ASCIIToUTF16("example2"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent3")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_HOSTED_APP, true);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent3")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_HOSTED_APP, true);
   service_->AddExtension(ext3.get());
   EXPECT_EQ(3u, registry()->enabled_extensions().size());
 
@@ -658,7 +655,7 @@
   scoped_refptr<Extension> ext =
       CreateExtension(base::ASCIIToUTF16("example"),
                       base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
-                      Manifest::EXTERNAL_COMPONENT,
+                      ManifestLocation::kExternalComponent,
                       extensions::Manifest::TYPE_EXTENSION, false);
   service_->AddExtension(ext.get());
 
@@ -824,8 +821,8 @@
 
   scoped_refptr<Extension> ext = CreateExtension(
       base::ASCIIToUTF16("example"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   ASSERT_TRUE(ext.get());
   service_->AddExtension(ext.get());
 
@@ -909,8 +906,8 @@
 
   scoped_refptr<Extension> ext = CreateExtension(
       base::ASCIIToUTF16("example"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   ASSERT_TRUE(ext.get());
   service_->AddExtension(ext.get());
 
@@ -970,8 +967,8 @@
 TEST_F(ProfileResetterTest, GetReadableFeedback) {
   scoped_refptr<Extension> ext = CreateExtension(
       base::WideToUTF16(L"Tiësto"),
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")), Manifest::UNPACKED,
-      extensions::Manifest::TYPE_EXTENSION, false);
+      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+      ManifestLocation::kUnpacked, extensions::Manifest::TYPE_EXTENSION, false);
   ASSERT_TRUE(ext.get());
   service_->AddExtension(ext.get());
 
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 7340e9b..53e926c 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -426,7 +426,7 @@
 
 void Profile::MaybeSendDestroyedNotification() {
   TRACE_EVENT1("shutdown", "Profile::MaybeSendDestroyedNotification", "profile",
-               static_cast<void*>(this));
+               this);
 
   if (!sent_destroyed_notification_) {
     sent_destroyed_notification_ = true;
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index c879241..1ceb1c8 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -25,20 +25,11 @@
 #include "extensions/common/constants.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/net/nss_service_chromeos_factory.h"
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
 using content::BrowserThread;
 
 void ProfileIOData::InitializeOnUIThread(Profile* profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  // TODO(https://crbug.com/1018972): Remove this line once NSS initialization
-  // no longer depends on the ResourceContext.
-  NssServiceChromeOSFactory::GetForContext(profile);
-#endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
   // Make sure the ResourceContext is initialized.  It's unclear if this is
   // still needed.
   content::BrowserContext::EnsureResourceContextInitialized(profile);
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
index 3a0cb59..9e7ace6b 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -3044,7 +3044,7 @@
 
 TEST_F('ChromeVoxBackgroundTest', 'VolumeChanges', function() {
   const mockFeedback = this.createMockFeedback();
-  this.runWithLoadedTree(``, function() {
+  this.runWithLoadedTree('<p>test</p>', function() {
     const bounds = ChromeVoxState.instance.getFocusBounds();
     mockFeedback.call(press(KeyCode.VOLUME_UP))
         .expectSpeech('Volume', 'Slider', /\d+%/)
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js
index b84a07cee..e5bef46 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -187,7 +187,7 @@
   /** private */
   onMoreFeaturesLinkClick_() {
     window.open(
-        'https://chrome.google.com/webstore/category/collection/accessibility');
+        'https://chrome.google.com/webstore/category/collection/3p_accessibility_extensions');
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_tether_item.js b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_tether_item.js
index ca19941..6b0cabcb 100644
--- a/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_tether_item.js
+++ b/chrome/browser/resources/settings/chromeos/multidevice_page/multidevice_tether_item.js
@@ -124,6 +124,7 @@
           deviceStates.find(deviceState => deviceState.type === kTether);
       this.deviceState_ = deviceState || {
         deviceState: chromeos.networkConfig.mojom.DeviceStateType.kDisabled,
+        inhibitReason: chromeos.networkConfig.mojom.InhibitReason.kNotInhibited,
         managedNetworkAvailable: false,
         scanning: false,
         simAbsent: false,
diff --git a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.html
index 653cb2d7..13e0396 100644
--- a/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.html
+++ b/chrome/browser/resources/settings/chromeos/os_a11y_page/manage_a11y_page.html
@@ -375,7 +375,7 @@
         if="[[shouldShowAdditionalFeaturesLink_(isGuest_, isKioskModeActive_)]]">
       <a class="settings-box inherit-color no-outline" tabindex="-1"
           id="additionalFeaturesLink" target="_blank"
-          href="https://chrome.google.com/webstore/category/collection/accessibility">
+          href="https://chrome.google.com/webstore/category/collection/3p_accessibility_extensions">
         <div class="start settings-box-text">
           $i18n{additionalFeaturesTitle}
           <div class="secondary" id="moreFeaturesSecondary">
diff --git a/chrome/browser/safe_browsing/ui_manager_unittest.cc b/chrome/browser/safe_browsing/ui_manager_unittest.cc
index b83aec7..01961bd 100644
--- a/chrome/browser/safe_browsing/ui_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/ui_manager_unittest.cc
@@ -573,7 +573,8 @@
   std::string error;
   scoped_refptr<extensions::Extension> app;
   app = extensions::Extension::Create(
-      base::FilePath(), extensions::Manifest::COMPONENT, manifest, 0, &error);
+      base::FilePath(), extensions::mojom::ManifestLocation::kComponent,
+      manifest, 0, &error);
   extensions::ProcessManager* extension_manager =
       extensions::ProcessManager::Get(web_contents()->GetBrowserContext());
   extension_manager->CreateBackgroundHost(app.get(), GURL("background.html"));
diff --git a/chrome/browser/sharing/proto/BUILD.gn b/chrome/browser/sharing/proto/BUILD.gn
index 67a6d2dc..e2bc2378 100644
--- a/chrome/browser/sharing/proto/BUILD.gn
+++ b/chrome/browser/sharing/proto/BUILD.gn
@@ -15,6 +15,6 @@
     "remote_copy_message.proto",
     "shared_clipboard_message.proto",
     "sharing_message.proto",
-    "sms_fetch_message.proto",
+    "sms_fetch_message_test_proto3_optional.proto",
   ]
 }
diff --git a/chrome/browser/sharing/proto/sharing_message.proto b/chrome/browser/sharing/proto/sharing_message.proto
index c388e7c3..51676df 100644
--- a/chrome/browser/sharing/proto/sharing_message.proto
+++ b/chrome/browser/sharing/proto/sharing_message.proto
@@ -11,7 +11,7 @@
 import "peer_connection_messages.proto";
 import "remote_copy_message.proto";
 import "shared_clipboard_message.proto";
-import "sms_fetch_message.proto";
+import "sms_fetch_message_test_proto3_optional.proto";
 
 package chrome_browser_sharing;
 
diff --git a/chrome/browser/sharing/proto/sms_fetch_message.proto b/chrome/browser/sharing/proto/sms_fetch_message_test_proto3_optional.proto
similarity index 65%
rename from chrome/browser/sharing/proto/sms_fetch_message.proto
rename to chrome/browser/sharing/proto/sms_fetch_message_test_proto3_optional.proto
index 652cd2fa..8c4ed2d 100644
--- a/chrome/browser/sharing/proto/sms_fetch_message.proto
+++ b/chrome/browser/sharing/proto/sms_fetch_message_test_proto3_optional.proto
@@ -28,4 +28,18 @@
   // The parsed one time code of the received SMS.
   // required
   string one_time_code = 2;
+  // Failure type of fetching a remote sms. This should be in sync with
+  // SmsFetchFailureType.
+  enum FailureType {
+    FAILURE_TYPE_UNSPECIFIED = 0;
+    SMS_NOT_PARSED_OTP_FORMAT_REGEX_NOT_MATCH = 1;
+    SMS_NOT_PARSED_HOST_AND_PORT_NOT_PARSED = 2;
+    SMS_NOT_PARSED_GURL_NOT_VALID = 3;
+    PROMPT_TIMEOUT = 4;
+    PROMPT_CANCELLED = 5;
+    BACKEND_NOT_AVAILABLE = 6;
+  }
+  // The failure type of the fetch request.
+  // optional
+  optional FailureType failure_type = 3;
 }
diff --git a/chrome/browser/sharing/sms/sms_fetch_request_handler.cc b/chrome/browser/sharing/sms/sms_fetch_request_handler.cc
index 0de8a8a7..6552547 100644
--- a/chrome/browser/sharing/sms/sms_fetch_request_handler.cc
+++ b/chrome/browser/sharing/sms/sms_fetch_request_handler.cc
@@ -4,8 +4,12 @@
 
 #include "chrome/browser/sharing/sms/sms_fetch_request_handler.h"
 
+#include "base/android/jni_string.h"
 #include "base/check.h"
-#include "chrome/browser/sharing/proto/sms_fetch_message.pb.h"
+#include "build/build_config.h"
+#include "chrome/android/chrome_jni_headers/SmsFetcherMessageHandler_jni.h"
+#include "chrome/browser/sharing/proto/sms_fetch_message_test_proto3_optional.pb.h"
+#include "components/url_formatter/elide_url.h"
 #include "content/public/browser/sms_fetcher.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -13,7 +17,10 @@
 SmsFetchRequestHandler::SmsFetchRequestHandler(content::SmsFetcher* fetcher)
     : fetcher_(fetcher) {}
 
-SmsFetchRequestHandler::~SmsFetchRequestHandler() = default;
+SmsFetchRequestHandler::~SmsFetchRequestHandler() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_SmsFetcherMessageHandler_reset(env);
+}
 
 void SmsFetchRequestHandler::OnMessage(
     chrome_browser_sharing::SharingMessage message,
@@ -30,6 +37,59 @@
   requests_.erase(request);
 }
 
+void SmsFetchRequestHandler::AskUserPermission(
+    const content::OriginList& origin_list,
+    const std::string& one_time_code) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
+  const std::u16string origin = url_formatter::FormatOriginForSecurityDisplay(
+      origin_list[0], url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  // If there is a notification from a previous request on screen this will
+  // overwrite that one with the new origin. In most cases where there's only
+  // one pending origin, the request will be removed when |SmsRetrieverClient|
+  // times out which would triggers |Request::OnFailure|.
+  // TODO(crbug.com/1138454): We should improve the infrastructure to be able to
+  // handle failures when there are multiple pending origins simultaneously.
+  Java_SmsFetcherMessageHandler_showNotification(
+      env, base::android::ConvertUTF8ToJavaString(env, one_time_code),
+      base::android::ConvertUTF16ToJavaString(env, origin),
+      reinterpret_cast<intptr_t>(this));
+}
+
+void SmsFetchRequestHandler::OnConfirm(JNIEnv* env, jstring j_origin) {
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
+  std::u16string origin =
+      base::android::ConvertJavaStringToUTF16(env, j_origin);
+  auto* request = GetRequest(origin);
+  DCHECK(request);
+  request->SendSuccessMessage();
+}
+
+void SmsFetchRequestHandler::OnDismiss(JNIEnv* env, jstring j_origin) {
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
+  std::u16string origin =
+      base::android::ConvertJavaStringToUTF16(env, j_origin);
+  auto* request = GetRequest(origin);
+  DCHECK(request);
+  // TODO(crbug.com/1015645): We should have a separate catergory for this type
+  // of failure.
+  request->SendFailureMessage(FailureType::kPromptCancelled);
+}
+
+SmsFetchRequestHandler::Request* SmsFetchRequestHandler::GetRequest(
+    const std::u16string& origin) {
+  for (auto& request : requests_) {
+    const auto& origin_list = request->origin_list();
+    // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
+    if (origin == url_formatter::FormatOriginForSecurityDisplay(
+                      origin_list[0],
+                      url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS)) {
+      return request.get();
+    }
+  }
+  return nullptr;
+}
+
 SmsFetchRequestHandler::Request::Request(
     SmsFetchRequestHandler* handler,
     content::SmsFetcher* fetcher,
@@ -39,31 +99,48 @@
       fetcher_(fetcher),
       origin_list_(content::OriginList{origin}),
       respond_callback_(std::move(respond_callback)) {
-  // TODO(1015645): Support iframe in cross-device WebOTP.
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
   fetcher_->Subscribe(origin_list_, this);
 }
 
 SmsFetchRequestHandler::Request::~Request() {
-  // TODO(1015645): Support iframe in cross-device WebOTP.
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
   fetcher_->Unsubscribe(origin_list_, this);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_SmsFetcherMessageHandler_dismissNotification(env);
 }
 
 void SmsFetchRequestHandler::Request::OnReceive(
     const content::OriginList& origin_list,
     const std::string& one_time_code,
     content::SmsFetcher::UserConsent consent_requirement) {
+  // TODO(crbug.com/1015645): Support iframe in cross-device WebOTP.
+  DCHECK_EQ(origin_list[0], origin_list_[0]);
+  one_time_code_ = one_time_code;
+  handler_->AskUserPermission(origin_list, one_time_code);
+}
+
+void SmsFetchRequestHandler::Request::SendSuccessMessage() {
   auto response = std::make_unique<chrome_browser_sharing::ResponseMessage>();
-  for (const auto& origin : origin_list)
+  for (const auto& origin : origin_list_)
     response->mutable_sms_fetch_response()->add_origin(origin.Serialize());
-  response->mutable_sms_fetch_response()->set_one_time_code(one_time_code);
+  response->mutable_sms_fetch_response()->set_one_time_code(one_time_code_);
 
   std::move(respond_callback_).Run(std::move(response));
-
   handler_->RemoveRequest(this);
 }
 
-// TODO(crbug.com/1015645): Add implementation.
-void SmsFetchRequestHandler::Request::OnFailure(
-    content::SmsFetcher::FailureType failure_type) {
-  NOTIMPLEMENTED();
+void SmsFetchRequestHandler::Request::SendFailureMessage(
+    FailureType failure_type) {
+  auto response = std::make_unique<chrome_browser_sharing::ResponseMessage>();
+  response->mutable_sms_fetch_response()->set_failure_type(
+      static_cast<chrome_browser_sharing::SmsFetchResponse::FailureType>(
+          failure_type));
+
+  std::move(respond_callback_).Run(std::move(response));
+  handler_->RemoveRequest(this);
+}
+
+void SmsFetchRequestHandler::Request::OnFailure(FailureType failure_type) {
+  SendFailureMessage(failure_type);
 }
diff --git a/chrome/browser/sharing/sms/sms_fetch_request_handler.h b/chrome/browser/sharing/sms/sms_fetch_request_handler.h
index cf6bae6..e9b8613 100644
--- a/chrome/browser/sharing/sms/sms_fetch_request_handler.h
+++ b/chrome/browser/sharing/sms/sms_fetch_request_handler.h
@@ -5,6 +5,9 @@
 #ifndef CHROME_BROWSER_SHARING_SMS_SMS_FETCH_REQUEST_HANDLER_H_
 #define CHROME_BROWSER_SHARING_SMS_SMS_FETCH_REQUEST_HANDLER_H_
 
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
 #include "base/bind.h"
 #include "base/containers/flat_set.h"
 #include "base/containers/unique_ptr_adapters.h"
@@ -21,14 +24,26 @@
 // Handles incoming messages for the sms fetcher feature.
 class SmsFetchRequestHandler : public SharingMessageHandler {
  public:
+  using FailureType = content::SmsFetchFailureType;
+
   explicit SmsFetchRequestHandler(content::SmsFetcher* fetcher);
   ~SmsFetchRequestHandler() override;
 
   // SharingMessageHandler
   void OnMessage(chrome_browser_sharing::SharingMessage message,
                  SharingMessageHandler::DoneCallback done_callback) override;
+  virtual void AskUserPermission(const content::OriginList&,
+                                 const std::string& one_time_code);
+  virtual void OnConfirm(JNIEnv*, jstring origin);
+  virtual void OnDismiss(JNIEnv*, jstring origin);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(SmsFetchRequestHandlerTest, Basic);
+  FRIEND_TEST_ALL_PREFIXES(SmsFetchRequestHandlerTest, OutOfOrder);
+  FRIEND_TEST_ALL_PREFIXES(SmsFetchRequestHandlerTest,
+                           SendSuccessMessageOnConfirm);
+  FRIEND_TEST_ALL_PREFIXES(SmsFetchRequestHandlerTest,
+                           SendFailureMessageOnDismiss);
   // Request represents an incoming request from a remote WebOTPService.
   // It manages subscribing and unsubscribing for SMSes in SmsFetcher and
   // responding to the callback.
@@ -45,23 +60,31 @@
     void OnReceive(const content::OriginList&,
                    const std::string& one_time_code,
                    content::SmsFetcher::UserConsent) override;
-    void OnFailure(content::SmsFetcher::FailureType failure_type) override;
+    void OnFailure(FailureType failure_type) override;
+    const content::OriginList& origin_list() const { return origin_list_; }
+    // OnReceive stashes the response and asks users for permission to send it
+    // to remote. Based on user's interaction, we send different responses back.
+    void SendSuccessMessage();
+    void SendFailureMessage(FailureType);
 
    private:
     SmsFetchRequestHandler* handler_;
     content::SmsFetcher* fetcher_;
     const content::OriginList origin_list_;
+    std::string one_time_code_;
     SharingMessageHandler::DoneCallback respond_callback_;
 
     DISALLOW_COPY_AND_ASSIGN(Request);
   };
 
   void RemoveRequest(Request* Request);
+  Request* GetRequest(const std::u16string& origin);
 
   // |fetcher_| is safe because it is owned by BrowserContext, which also
   // owns (transitively, via SharingService) this class.
   content::SmsFetcher* fetcher_;
   base::flat_set<std::unique_ptr<Request>, base::UniquePtrComparator> requests_;
+
   base::WeakPtrFactory<SmsFetchRequestHandler> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(SmsFetchRequestHandler);
diff --git a/chrome/browser/sharing/sms/sms_fetch_request_handler_unittest.cc b/chrome/browser/sharing/sms/sms_fetch_request_handler_unittest.cc
index 23526e96..d7cec37 100644
--- a/chrome/browser/sharing/sms/sms_fetch_request_handler_unittest.cc
+++ b/chrome/browser/sharing/sms/sms_fetch_request_handler_unittest.cc
@@ -3,11 +3,17 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/sharing/sms/sms_fetch_request_handler.h"
+#include <string>
 
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "chrome/browser/sharing/proto/sharing_message.pb.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
+#include "components/url_formatter/elide_url.h"
 #include "content/public/browser/sms_fetcher.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -48,6 +54,23 @@
   DISALLOW_COPY_AND_ASSIGN(MockSmsFetcher);
 };
 
+class MockSmsFetchRequestHandler : public SmsFetchRequestHandler {
+ public:
+  explicit MockSmsFetchRequestHandler(content::SmsFetcher* fetcher)
+      : SmsFetchRequestHandler(fetcher) {}
+  ~MockSmsFetchRequestHandler() = default;
+
+  MOCK_METHOD2(AskUserPermission,
+               void(const content::OriginList&,
+                    const std::string& one_time_code));
+  MOCK_METHOD2(OnConfirm, void(JNIEnv*, jstring origin));
+  MOCK_METHOD2(OnDismiss, void(JNIEnv*, jstring origin));
+
+  MockSmsFetchRequestHandler(const MockSmsFetchRequestHandler&) = delete;
+  MockSmsFetchRequestHandler& operator=(const MockSmsFetchRequestHandler&) =
+      delete;
+};
+
 SharingMessage CreateRequest(const std::string& origin) {
   SharingMessage message;
   message.mutable_sms_fetch_request()->set_origin(origin);
@@ -60,7 +83,15 @@
   base::test::SingleThreadTaskEnvironment task_environment;
   StrictMock<MockSmsFetcher> fetcher;
   SmsFetchRequestHandler handler(&fetcher);
-  SharingMessage message = CreateRequest("https://a.com");
+  const std::string origin = "https://a.com";
+  SharingMessage message = CreateRequest(origin);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const std::u16string formatted_origin =
+      url_formatter::FormatOriginForSecurityDisplay(
+          url::Origin::Create(GURL(origin)),
+          url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  base::android::ScopedJavaLocalRef<jstring> j_origin =
+      base::android::ConvertUTF16ToJavaString(env, formatted_origin);
 
   base::RunLoop loop;
 
@@ -76,9 +107,9 @@
         loop.Quit();
       }));
 
-  subscriber->OnReceive(
-      content::OriginList{url::Origin::Create(GURL("https://a.com"))}, "123",
-      SmsFetcher::UserConsent::kNotObtained);
+  subscriber->OnReceive(content::OriginList{url::Origin::Create(GURL(origin))},
+                        "123", SmsFetcher::UserConsent::kNotObtained);
+  handler.OnConfirm(env, j_origin.obj());
   loop.Run();
 }
 
@@ -86,7 +117,24 @@
   base::test::SingleThreadTaskEnvironment task_environment;
   StrictMock<MockSmsFetcher> fetcher;
   SmsFetchRequestHandler handler(&fetcher);
-  SharingMessage message = CreateRequest("https://a.com");
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const std::string origin1 = "https://a.com";
+  SharingMessage message1 = CreateRequest(origin1);
+  const std::u16string formatted_origin1 =
+      url_formatter::FormatOriginForSecurityDisplay(
+          url::Origin::Create(GURL(origin1)),
+          url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  base::android::ScopedJavaLocalRef<jstring> j_origin1 =
+      base::android::ConvertUTF16ToJavaString(env, formatted_origin1);
+
+  const std::string origin2 = "https://b.com";
+  SharingMessage message2 = CreateRequest(origin2);
+  const std::u16string formatted_origin2 =
+      url_formatter::FormatOriginForSecurityDisplay(
+          url::Origin::Create(GURL(origin2)),
+          url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  base::android::ScopedJavaLocalRef<jstring> j_origin2 =
+      base::android::ConvertUTF16ToJavaString(env, formatted_origin2);
 
   base::RunLoop loop1;
 
@@ -95,7 +143,7 @@
   EXPECT_CALL(fetcher, Unsubscribe(_, _)).Times(2);
 
   handler.OnMessage(
-      message,
+      message1,
       BindLambdaForTesting([&loop1](std::unique_ptr<ResponseMessage> response) {
         EXPECT_TRUE(response->has_sms_fetch_response());
         EXPECT_EQ("1", response->sms_fetch_response().one_time_code());
@@ -108,21 +156,21 @@
   EXPECT_CALL(fetcher, Subscribe(_, _)).WillOnce(SaveArg<1>(&request2));
 
   handler.OnMessage(
-      message,
+      message2,
       BindLambdaForTesting([&loop2](std::unique_ptr<ResponseMessage> response) {
         EXPECT_TRUE(response->has_sms_fetch_response());
         EXPECT_EQ("2", response->sms_fetch_response().one_time_code());
         loop2.Quit();
       }));
 
-  request2->OnReceive(
-      content::OriginList{url::Origin::Create(GURL("https://a.com"))}, "2",
-      SmsFetcher::UserConsent::kNotObtained);
+  request2->OnReceive(content::OriginList{url::Origin::Create(GURL(origin2))},
+                      "2", SmsFetcher::UserConsent::kNotObtained);
+  handler.OnConfirm(env, j_origin2.obj());
   loop2.Run();
 
-  request1->OnReceive(
-      content::OriginList{url::Origin::Create(GURL("https://a.com"))}, "1",
-      SmsFetcher::UserConsent::kNotObtained);
+  request1->OnReceive(content::OriginList{url::Origin::Create(GURL(origin1))},
+                      "1", SmsFetcher::UserConsent::kNotObtained);
+  handler.OnConfirm(env, j_origin1.obj());
   loop1.Run();
 }
 
@@ -145,3 +193,91 @@
       message,
       BindLambdaForTesting([&](std::unique_ptr<ResponseMessage> response) {}));
 }
+
+TEST(SmsFetchRequestHandlerTest, AskUserPermissionOnReceive) {
+  base::test::SingleThreadTaskEnvironment task_environment;
+  StrictMock<MockSmsFetcher> fetcher;
+  MockSmsFetchRequestHandler handler(&fetcher);
+  SharingMessage message = CreateRequest("https://a.com");
+
+  SmsFetcher::Subscriber* subscriber;
+  EXPECT_CALL(fetcher, Subscribe(_, _)).WillOnce(SaveArg<1>(&subscriber));
+  EXPECT_CALL(handler, AskUserPermission);
+  EXPECT_CALL(fetcher, Unsubscribe);
+
+  handler.OnMessage(message, base::DoNothing());
+
+  subscriber->OnReceive(
+      content::OriginList{url::Origin::Create(GURL("https://a.com"))}, "123",
+      SmsFetcher::UserConsent::kNotObtained);
+}
+
+TEST(SmsFetchRequestHandlerTest, SendSuccessMessageOnConfirm) {
+  base::test::SingleThreadTaskEnvironment task_environment;
+  StrictMock<MockSmsFetcher> fetcher;
+  SmsFetchRequestHandler handler(&fetcher);
+  const std::string origin = "https://a.com";
+  SharingMessage message = CreateRequest(origin);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const std::u16string formatted_origin =
+      url_formatter::FormatOriginForSecurityDisplay(
+          url::Origin::Create(GURL(origin)),
+          url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  base::android::ScopedJavaLocalRef<jstring> j_origin =
+      base::android::ConvertUTF16ToJavaString(env, formatted_origin);
+
+  base::RunLoop loop;
+
+  SmsFetcher::Subscriber* subscriber;
+  EXPECT_CALL(fetcher, Subscribe(_, _)).WillOnce(SaveArg<1>(&subscriber));
+  EXPECT_CALL(fetcher, Unsubscribe);
+
+  handler.OnMessage(
+      message,
+      BindLambdaForTesting([&loop](std::unique_ptr<ResponseMessage> response) {
+        EXPECT_TRUE(response->has_sms_fetch_response());
+        EXPECT_EQ("123", response->sms_fetch_response().one_time_code());
+        loop.Quit();
+      }));
+
+  subscriber->OnReceive(content::OriginList{url::Origin::Create(GURL(origin))},
+                        "123", SmsFetcher::UserConsent::kNotObtained);
+  handler.OnConfirm(env, j_origin.obj());
+  loop.Run();
+}
+
+TEST(SmsFetchRequestHandlerTest, SendFailureMessageOnDismiss) {
+  base::test::SingleThreadTaskEnvironment task_environment;
+  StrictMock<MockSmsFetcher> fetcher;
+  SmsFetchRequestHandler handler(&fetcher);
+  const std::string origin = "https://a.com";
+  SharingMessage message = CreateRequest(origin);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  const std::u16string formatted_origin =
+      url_formatter::FormatOriginForSecurityDisplay(
+          url::Origin::Create(GURL(origin)),
+          url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
+  base::android::ScopedJavaLocalRef<jstring> j_origin =
+      base::android::ConvertUTF16ToJavaString(env, formatted_origin);
+
+  base::RunLoop loop;
+
+  SmsFetcher::Subscriber* subscriber;
+  EXPECT_CALL(fetcher, Subscribe(_, _)).WillOnce(SaveArg<1>(&subscriber));
+  EXPECT_CALL(fetcher, Unsubscribe);
+
+  handler.OnMessage(
+      message,
+      BindLambdaForTesting([&loop](std::unique_ptr<ResponseMessage> response) {
+        EXPECT_TRUE(response->has_sms_fetch_response());
+        EXPECT_EQ(content::SmsFetchFailureType::kPromptCancelled,
+                  static_cast<content::SmsFetchFailureType>(
+                      response->sms_fetch_response().failure_type()));
+        loop.Quit();
+      }));
+
+  subscriber->OnReceive(content::OriginList{url::Origin::Create(GURL(origin))},
+                        "123", SmsFetcher::UserConsent::kNotObtained);
+  handler.OnDismiss(env, j_origin.obj());
+  loop.Run();
+}
diff --git a/chrome/browser/sharing/sms/sms_remote_fetcher.cc b/chrome/browser/sharing/sms/sms_remote_fetcher.cc
index 7d8f63c..902e8c23 100644
--- a/chrome/browser/sharing/sms/sms_remote_fetcher.cc
+++ b/chrome/browser/sharing/sms/sms_remote_fetcher.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/sharing/sms/sms_flags.h"
 #include "components/sync_device_info/device_info.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/sms_fetcher.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -21,10 +22,14 @@
 void FetchRemoteSms(
     content::BrowserContext* context,
     const url::Origin& origin,
-    base::OnceCallback<void(base::Optional<OriginList>,
-                            base::Optional<std::string>)> callback) {
+    base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
+                            base::Optional<std::string>,
+                            base::Optional<content::SmsFetchFailureType>)>
+        callback) {
+  // TODO(crbug.com/1015645): We should have a new failure type when the feature
+  // is disabled or no device is available.
   if (!base::FeatureList::IsEnabled(kWebOTPCrossDevice)) {
-    std::move(callback).Run(base::nullopt, base::nullopt);
+    std::move(callback).Run(base::nullopt, base::nullopt, base::nullopt);
     return;
   }
 
@@ -36,7 +41,7 @@
 
   if (devices.empty()) {
     // No devices available to call.
-    std::move(callback).Run(base::nullopt, base::nullopt);
+    std::move(callback).Run(base::nullopt, base::nullopt, base::nullopt);
     return;
   }
 
@@ -53,25 +58,36 @@
       *device.get(), base::TimeDelta::FromSeconds(kDefaultTimeoutSeconds),
       std::move(request),
       base::BindOnce(
-          [](base::OnceCallback<void(base::Optional<OriginList>,
-                                     base::Optional<std::string>)> callback,
+          [](base::OnceCallback<void(
+                 base::Optional<std::vector<url::Origin>>,
+                 base::Optional<std::string>,
+                 base::Optional<content::SmsFetchFailureType>)> callback,
              SharingSendMessageResult result,
              std::unique_ptr<chrome_browser_sharing::ResponseMessage>
                  response) {
             if (result != SharingSendMessageResult::kSuccessful) {
-              std::move(callback).Run(base::nullopt, base::nullopt);
+              std::move(callback).Run(base::nullopt, base::nullopt,
+                                      base::nullopt);
               return;
             }
 
             DCHECK(response);
             DCHECK(response->has_sms_fetch_response());
+            if (response->sms_fetch_response().has_failure_type()) {
+              std::move(callback).Run(
+                  base::nullopt, base::nullopt,
+                  static_cast<content::SmsFetchFailureType>(
+                      response->sms_fetch_response().failure_type()));
+              return;
+            }
             auto origin_strings = response->sms_fetch_response().origin();
-            OriginList origin_list;
+            std::vector<url::Origin> origin_list;
             for (auto origin_string : origin_strings)
               origin_list.push_back(url::Origin::Create(GURL(origin_string)));
 
             std::move(callback).Run(
-                origin_list, response->sms_fetch_response().one_time_code());
+                origin_list, response->sms_fetch_response().one_time_code(),
+                base::nullopt);
           },
           std::move(callback)));
 }
diff --git a/chrome/browser/sharing/sms/sms_remote_fetcher.h b/chrome/browser/sharing/sms/sms_remote_fetcher.h
index 12bd1de..180c93e 100644
--- a/chrome/browser/sharing/sms/sms_remote_fetcher.h
+++ b/chrome/browser/sharing/sms/sms_remote_fetcher.h
@@ -12,18 +12,19 @@
 
 namespace content {
 class BrowserContext;
+enum class SmsFetchFailureType;
 }
 
 namespace url {
 class Origin;
 }
 
-using OriginList = std::vector<url::Origin>;
-
 // Uses the SharingService to fetch an SMS from a remote device.
-void FetchRemoteSms(content::BrowserContext* context,
-                    const url::Origin& origin,
-                    base::OnceCallback<void(base::Optional<OriginList>,
-                                            base::Optional<std::string>)>);
+void FetchRemoteSms(
+    content::BrowserContext* context,
+    const url::Origin& origin,
+    base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
+                            base::Optional<std::string>,
+                            base::Optional<content::SmsFetchFailureType>)>);
 
 #endif  // CHROME_BROWSER_SHARING_SMS_SMS_REMOTE_FETCHER_H_
diff --git a/chrome/browser/sharing/sms/sms_remote_fetcher_unittest.cc b/chrome/browser/sharing/sms/sms_remote_fetcher_unittest.cc
index d8c5108..6c4dda6 100644
--- a/chrome/browser/sharing/sms/sms_remote_fetcher_unittest.cc
+++ b/chrome/browser/sharing/sms/sms_remote_fetcher_unittest.cc
@@ -52,11 +52,13 @@
 
   FetchRemoteSms(
       &profile, GetOriginForURL("a.com"),
-      BindLambdaForTesting([&loop](base::Optional<OriginList>,
-                                   base::Optional<std::string> result) {
-        ASSERT_FALSE(result);
-        loop.Quit();
-      }));
+      BindLambdaForTesting(
+          [&loop](base::Optional<std::vector<url::Origin>>,
+                  base::Optional<std::string> result,
+                  base::Optional<content::SmsFetchFailureType> failure_type) {
+            ASSERT_FALSE(result);
+            loop.Quit();
+          }));
 
   loop.Run();
 }
@@ -78,11 +80,13 @@
 
   FetchRemoteSms(
       &profile, GetOriginForURL("a.com"),
-      BindLambdaForTesting([&loop](base::Optional<OriginList>,
-                                   base::Optional<std::string> result) {
-        ASSERT_FALSE(result);
-        loop.Quit();
-      }));
+      BindLambdaForTesting(
+          [&loop](base::Optional<std::vector<url::Origin>>,
+                  base::Optional<std::string> result,
+                  base::Optional<content::SmsFetchFailureType> failure_type) {
+            ASSERT_FALSE(result);
+            loop.Quit();
+          }));
 
   loop.Run();
 }
@@ -117,12 +121,14 @@
 
   FetchRemoteSms(
       &profile, GetOriginForURL("a.com"),
-      BindLambdaForTesting([&loop](base::Optional<OriginList>,
-                                   base::Optional<std::string> result) {
-        ASSERT_TRUE(result);
-        ASSERT_EQ("ABC", result);
-        loop.Quit();
-      }));
+      BindLambdaForTesting(
+          [&loop](base::Optional<std::vector<url::Origin>>,
+                  base::Optional<std::string> result,
+                  base::Optional<content::SmsFetchFailureType> failure_type) {
+            ASSERT_TRUE(result);
+            ASSERT_EQ("ABC", result);
+            loop.Quit();
+          }));
 
   loop.Run();
 }
@@ -155,11 +161,13 @@
 
   FetchRemoteSms(
       &profile, GetOriginForURL("a.com"),
-      BindLambdaForTesting([&loop](base::Optional<OriginList>,
-                                   base::Optional<std::string> result) {
-        ASSERT_FALSE(result);
-        loop.Quit();
-      }));
+      BindLambdaForTesting(
+          [&loop](base::Optional<std::vector<url::Origin>>,
+                  base::Optional<std::string> result,
+                  base::Optional<content::SmsFetchFailureType> failure_type) {
+            ASSERT_FALSE(result);
+            loop.Quit();
+          }));
 
   loop.Run();
 }
diff --git a/chrome/browser/site_isolation/site_details.cc b/chrome/browser/site_isolation/site_details.cc
index 207b05b..fe0af82 100644
--- a/chrome/browser/site_isolation/site_details.cc
+++ b/chrome/browser/site_isolation/site_details.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/site_isolation/site_details.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -25,6 +26,8 @@
 content::SiteInstance* DeterminePrimarySiteInstance(
     content::SiteInstance* site_instance,
     SiteData* site_data) {
+  TRACE_EVENT1("navigation", "DeterminePrimarySiteInstance", "site_instance",
+               site_instance);
   // Find the BrowsingInstance this WebContents belongs to by iterating over
   // the "primary" SiteInstances of each BrowsingInstance we've seen so far.
   for (auto& entry : site_data->browsing_instances) {
diff --git a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
index b8bc673..a6b003be 100644
--- a/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
+++ b/chrome/browser/sync/glue/extensions_activity_monitor_unittest.cc
@@ -45,7 +45,7 @@
   value.SetString(keys::kName, name);
   std::string error;
   scoped_refptr<Extension> extension(Extension::Create(
-      path, extensions::Manifest::INVALID_LOCATION, value,
+      path, extensions::mojom::ManifestLocation::kInvalidLocation, value,
       Extension::NO_FLAGS, &error));
   EXPECT_TRUE(error.empty());
   return extension;
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index cd32b56..6e5567ee 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -376,9 +376,9 @@
     return nullptr;
   }
   std::string error;
-  scoped_refptr<Extension> extension =
-      Extension::Create(extension_dir, Manifest::INTERNAL, source,
-                        Extension::NO_FLAGS, &error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      extension_dir, extensions::mojom::ManifestLocation::kInternal, source,
+      Extension::NO_FLAGS, &error);
   if (!error.empty()) {
     ADD_FAILURE() << error;
     return nullptr;
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index a930581..cbd2c6ec 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -242,9 +242,9 @@
       base::DictionaryValue::From(deserializer.Deserialize(NULL, &error));
   EXPECT_EQ("", error);
   ASSERT_TRUE(valid_value.get());
-  scoped_refptr<Extension> extension(
-      Extension::Create(extension_path, extensions::Manifest::INVALID_LOCATION,
-                        *valid_value, Extension::NO_FLAGS, &error));
+  scoped_refptr<Extension> extension(Extension::Create(
+      extension_path, extensions::mojom::ManifestLocation::kInvalidLocation,
+      *valid_value, Extension::NO_FLAGS, &error));
   ASSERT_TRUE(extension.get());
   ASSERT_EQ("", error);
   BrowserThemePack::BuildFromExtension(extension.get(), pack);
diff --git a/chrome/browser/themes/theme_syncable_service_unittest.cc b/chrome/browser/themes/theme_syncable_service_unittest.cc
index 0bcdfc9..f2ecccf 100644
--- a/chrome/browser/themes/theme_syncable_service_unittest.cc
+++ b/chrome/browser/themes/theme_syncable_service_unittest.cc
@@ -156,7 +156,7 @@
 scoped_refptr<extensions::Extension> MakeThemeExtension(
     const base::FilePath& extension_path,
     const string& name,
-    extensions::Manifest::Location location,
+    extensions::mojom::ManifestLocation location,
     const string& update_url) {
   base::DictionaryValue source;
   source.SetString(extensions::manifest_keys::kName, name);
@@ -232,8 +232,8 @@
   }
 
   // Overridden in PolicyInstalledThemeTest below.
-  virtual extensions::Manifest::Location GetThemeLocation() {
-    return extensions::Manifest::INTERNAL;
+  virtual extensions::mojom::ManifestLocation GetThemeLocation() {
+    return extensions::mojom::ManifestLocation::kInternal;
   }
 
   FakeThemeService* BuildForProfile(Profile* profile) {
@@ -282,8 +282,8 @@
 };
 
 class PolicyInstalledThemeTest : public ThemeSyncableServiceTest {
-  extensions::Manifest::Location GetThemeLocation() override {
-    return extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD;
+  extensions::mojom::ManifestLocation GetThemeLocation() override {
+    return extensions::mojom::ManifestLocation::kExternalPolicyDownload;
   }
 };
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ff38043..98bb47a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1716,6 +1716,7 @@
       "app_list/app_sync_ui_state.h",
       "app_list/app_sync_ui_state_factory.cc",
       "app_list/app_sync_ui_state_factory.h",
+      "app_list/app_sync_ui_state_observer.cc",
       "app_list/app_sync_ui_state_observer.h",
       "app_list/app_sync_ui_state_watcher.cc",
       "app_list/app_sync_ui_state_watcher.h",
@@ -2715,6 +2716,7 @@
       "//chromeos/components/multidevice/logging",
       "//chromeos/components/network_ui:network_diagnostics_resource_provider",
       "//chromeos/components/network_ui:network_health_resource_provider",
+      "//chromeos/components/personalization_app",
       "//chromeos/components/phonehub",
       "//chromeos/components/phonehub:debug",
       "//chromeos/components/print_management",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 771e53b..00f3f8f6 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3990,6 +3990,14 @@
         Send text to Your Devices
       </message>
 
+      <!-- Sms Fetcher -->
+      <message name="IDS_SMS_FETCHER_NOTIFICATION_TITLE" translateable="false" desc="Title text shown when the browser has received an SMS on the user's behalf.">
+        Tap to verify your phone number on desktop
+      </message>
+      <message name="IDS_SMS_FETCHER_NOTIFICATION_TEXT" translateable="false" desc="Content text shown when the browser has received an SMS on the user's behalf.">
+        <ph name="ONE_TIME_CODE">%1$s<ex>123</ex></ph> is your code for <ph name="ORIGIN">%2$s<ex>example.com</ex></ph>
+      </message>
+
       <!-- Interventions -->
       <message name="IDS_REDIRECT_BLOCKED_MESSAGE" desc="The message stating that a redirect (noun) was blocked on this page. This will be followed on a separate line with the address the user was being redirected to.">
          Redirect blocked:
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
index 9deb123..49546bb 100644
--- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc
+++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -250,8 +250,8 @@
     value.GetAsDictionary(&dictionary_manifest);
     std::string error;
     return extensions::Extension::Create(
-        path.DirName(), extensions::Manifest::INTERNAL, *dictionary_manifest,
-        extensions::Extension::NO_FLAGS, app_id, &error);
+        path.DirName(), extensions::mojom::ManifestLocation::kInternal,
+        *dictionary_manifest, extensions::Extension::NO_FLAGS, app_id, &error);
   }
 
   void TestExtensionApp(const std::string& app_id,
@@ -299,7 +299,7 @@
     value.SetString("version", "0.0");
     value.SetString("app.launch.web_url", "http://google.com");
     scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
-        base::FilePath(), extensions::Manifest::INTERNAL, value,
+        base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
         extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
         extension_misc::kChromeAppId, &err);
     EXPECT_EQ(err, "");
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index 9bd250b8..5121836 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -227,6 +227,12 @@
 
 AppListSyncableService::SyncItem::~SyncItem() = default;
 
+// AppListSyncableService::Observer
+
+AppListSyncableService::Observer::~Observer() {
+  // TODO(jamescook): Add CHECK(!IsInObserverList()).
+}
+
 // AppListSyncableService::ModelUpdaterObserver
 
 class AppListSyncableService::ModelUpdaterObserver
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.h b/chrome/browser/ui/app_list/app_list_syncable_service.h
index 1d2140a5..e426ff45 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.h
@@ -15,6 +15,7 @@
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/one_shot_event.h"
 #include "build/build_config.h"
 #include "chrome/browser/sync/glue/sync_start_util.h"
@@ -64,13 +65,13 @@
     std::string ToString() const;
   };
 
-  class Observer {
+  class Observer : public base::CheckedObserver {
    public:
     // Notifies that sync model was updated.
     virtual void OnSyncModelUpdated() = 0;
 
    protected:
-    virtual ~Observer() = default;
+    ~Observer() override;
   };
 
   // An app list model updater factory function used by tests.
@@ -357,7 +358,7 @@
   base::OnceClosure wait_until_ready_to_sync_cb_;
 
   // List of observers.
-  base::ObserverList<Observer>::Unchecked observer_list_;
+  base::ObserverList<Observer> observer_list_;
   base::OneShotEvent on_initialized_;
 
   base::WeakPtrFactory<AppListSyncableService> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index a67bb8a..0b7c11d 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -52,7 +52,8 @@
   value.SetString("version", "0.0");
   value.SetString("app.launch.web_url", "http://google.com");
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
-      base::FilePath(), extensions::Manifest::INTERNAL, value, flags, id, &err);
+      base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
+      flags, id, &err);
   EXPECT_EQ(err, "");
   return app;
 }
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
index ece2606..224e603 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_model_builder_unittest.cc
@@ -128,7 +128,7 @@
   value.SetString("version", version);
   value.SetString("app.launch.web_url", url);
   scoped_refptr<extensions::Extension> app = extensions::Extension::Create(
-      base::FilePath(), extensions::Manifest::INTERNAL, value,
+      base::FilePath(), extensions::mojom::ManifestLocation::kInternal, value,
       extensions::Extension::WAS_INSTALLED_BY_DEFAULT, id, &err);
   EXPECT_EQ(err, "");
   return app;
diff --git a/chrome/browser/ui/app_list/app_service/app_service_context_menu.h b/chrome/browser/ui/app_list/app_service/app_service_context_menu.h
index a746579..bd7af3f0 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_context_menu.h
+++ b/chrome/browser/ui/app_list/app_service/app_service_context_menu.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 #include "chrome/browser/ui/app_list/app_context_menu.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state.h b/chrome/browser/ui/app_list/app_sync_ui_state.h
index 90507c2..38f88de 100644
--- a/chrome/browser/ui/app_list/app_sync_ui_state.h
+++ b/chrome/browser/ui/app_list/app_sync_ui_state.h
@@ -87,7 +87,7 @@
   base::OneShotTimer max_syncing_status_timer_;
 
   Status status_;
-  base::ObserverList<AppSyncUIStateObserver>::Unchecked observers_;
+  base::ObserverList<AppSyncUIStateObserver> observers_;
 
   extensions::ExtensionRegistry* extension_registry_;
 
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state_observer.cc b/chrome/browser/ui/app_list/app_sync_ui_state_observer.cc
new file mode 100644
index 0000000..29960a9
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_sync_ui_state_observer.cc
@@ -0,0 +1,9 @@
+// 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/ui/app_list/app_sync_ui_state_observer.h"
+
+AppSyncUIStateObserver::~AppSyncUIStateObserver() {
+  // TODO(jamescook): Add CHECK(!IsInObserverList()).
+}
diff --git a/chrome/browser/ui/app_list/app_sync_ui_state_observer.h b/chrome/browser/ui/app_list/app_sync_ui_state_observer.h
index d13820e..59c144d 100644
--- a/chrome/browser/ui/app_list/app_sync_ui_state_observer.h
+++ b/chrome/browser/ui/app_list/app_sync_ui_state_observer.h
@@ -5,13 +5,15 @@
 #ifndef CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_OBSERVER_H_
 #define CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_OBSERVER_H_
 
-class AppSyncUIStateObserver {
+#include "base/observer_list_types.h"
+
+class AppSyncUIStateObserver : public base::CheckedObserver {
  public:
   // Invoked when the UI status of app sync has changed.
   virtual void OnAppSyncUIStatusChanged() = 0;
 
  protected:
-  virtual ~AppSyncUIStateObserver() {}
+  ~AppSyncUIStateObserver() override;
 };
 
 #endif  // CHROME_BROWSER_UI_APP_LIST_APP_SYNC_UI_STATE_OBSERVER_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_launcher.cc b/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
index ff1c09e7..e5b81d64 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
@@ -5,39 +5,28 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_launcher.h"
 
 #include <memory>
-#include <utility>
 
-#include "chrome/browser/apps/app_service/app_service_proxy.h"
-#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
-#include "chrome/browser/apps/app_service/launch_utils.h"
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "ui/events/event_constants.h"
 
 ArcAppLauncher::ArcAppLauncher(content::BrowserContext* context,
                                const std::string& app_id,
-                               apps::mojom::IntentPtr launch_intent,
+                               const base::Optional<std::string>& launch_intent,
                                bool deferred_launch_allowed,
                                int64_t display_id,
-                               apps::mojom::LaunchSource launch_source)
+                               arc::UserInteractionType interaction)
     : context_(context),
       app_id_(app_id),
-      launch_intent_(std::move(launch_intent)),
+      launch_intent_(launch_intent),
       deferred_launch_allowed_(deferred_launch_allowed),
       display_id_(display_id),
-      launch_source_(launch_source) {
+      interaction_(interaction) {
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
   DCHECK(prefs);
 
   std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id_);
-  if (!app_info ||
-      !MaybeLaunchApp(app_id, *app_info, apps::mojom::Readiness::kUnknown))
+  if (!app_info || !MaybeLaunchApp(app_id, *app_info))
     prefs->AddObserver(this);
-
-  auto* profile = Profile::FromBrowserContext(context_);
-  DCHECK(
-      apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile));
-  Observe(&apps::AppServiceProxyFactory::GetForProfile(profile)
-               ->AppRegistryCache());
 }
 
 ArcAppLauncher::~ArcAppLauncher() {
@@ -52,82 +41,32 @@
 void ArcAppLauncher::OnAppRegistered(
     const std::string& app_id,
     const ArcAppListPrefs::AppInfo& app_info) {
-  MaybeLaunchApp(app_id, app_info, apps::mojom::Readiness::kUnknown);
+  MaybeLaunchApp(app_id, app_info);
 }
 
 void ArcAppLauncher::OnAppStatesChanged(
     const std::string& app_id,
     const ArcAppListPrefs::AppInfo& app_info) {
-  MaybeLaunchApp(app_id, app_info, apps::mojom::Readiness::kUnknown);
-}
-
-void ArcAppLauncher::OnAppUpdate(const apps::AppUpdate& update) {
-  if (update.AppId() != app_id_ ||
-      update.Readiness() != apps::mojom::Readiness::kReady) {
-    return;
-  }
-
-  ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
-  DCHECK(prefs);
-
-  const std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
-      prefs->GetApp(app_id_);
-  if (!app_info)
-    return;
-
-  MaybeLaunchApp(app_id_, *app_info, apps::mojom::Readiness::kReady);
-}
-
-void ArcAppLauncher::OnAppRegistryCacheWillBeDestroyed(
-    apps::AppRegistryCache* cache) {
-  Observe(nullptr);
+  MaybeLaunchApp(app_id, app_info);
 }
 
 bool ArcAppLauncher::MaybeLaunchApp(const std::string& app_id,
-                                    const ArcAppListPrefs::AppInfo& app_info,
-                                    apps::mojom::Readiness readiness) {
-  if (app_launched_)
-    return true;
+                                    const ArcAppListPrefs::AppInfo& app_info) {
+  DCHECK(!app_launched_);
 
   if (app_id != app_id_ || (!app_info.ready && !deferred_launch_allowed_) ||
       app_info.suspended) {
     return false;
   }
 
-  auto* profile = Profile::FromBrowserContext(context_);
-  DCHECK(
-      apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile));
-  auto* proxy = apps::AppServiceProxyFactory::GetForProfile(profile);
-  if (readiness == apps::mojom::Readiness::kUnknown) {
-    if (proxy->AppRegistryCache().GetAppType(app_id) ==
-        apps::mojom::AppType::kUnknown) {
-      return false;
-    }
-
-    apps::mojom::Readiness readiness = apps::mojom::Readiness::kUnknown;
-    proxy->AppRegistryCache().ForOneApp(
-        app_id, [&readiness](const apps::AppUpdate& update) {
-          readiness = update.Readiness();
-        });
-
-    if (readiness != apps::mojom::Readiness::kReady)
-      return false;
-  } else if (readiness != apps::mojom::Readiness::kReady) {
-    return false;
-  }
-
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(context_);
   DCHECK(prefs && prefs->GetApp(app_id_));
   prefs->RemoveObserver(this);
-  Observe(nullptr);
 
-  if (launch_intent_) {
-    proxy->LaunchAppWithIntent(app_id_, ui::EF_NONE, std::move(launch_intent_),
-                               launch_source_,
-                               apps::MakeWindowInfo(display_id_));
-  } else {
-    proxy->Launch(app_id_, ui::EF_NONE, launch_source_,
-                  apps::MakeWindowInfo(display_id_));
+  if (!arc::LaunchAppWithIntent(context_, app_id_, launch_intent_, ui::EF_NONE,
+                                interaction_,
+                                arc::MakeWindowInfo(display_id_))) {
+    VLOG(2) << "Failed to launch app: " + app_id_ + ".";
   }
 
   app_launched_ = true;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_launcher.h b/chrome/browser/ui/app_list/arc/arc_app_launcher.h
index 3c986a7..b6de9db 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_launcher.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_launcher.h
@@ -14,8 +14,6 @@
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "components/arc/metrics/arc_metrics_constants.h"
-#include "components/services/app_service/public/cpp/app_registry_cache.h"
-#include "components/services/app_service/public/mojom/types.mojom.h"
 
 namespace content {
 class BrowserContext;
@@ -23,15 +21,14 @@
 
 // Helper class for deferred ARC app launching in case app is not ready on the
 // moment of request.
-class ArcAppLauncher : public ArcAppListPrefs::Observer,
-                       public apps::AppRegistryCache::Observer {
+class ArcAppLauncher : public ArcAppListPrefs::Observer {
  public:
   ArcAppLauncher(content::BrowserContext* context,
                  const std::string& app_id,
-                 apps::mojom::IntentPtr launch_intent,
+                 const base::Optional<std::string>& launch_intent,
                  bool deferred_launch_allowed,
                  int64_t display_id,
-                 apps::mojom::LaunchSource launch_source);
+                 arc::UserInteractionType interaction);
   ~ArcAppLauncher() override;
 
   bool app_launched() const { return app_launched_; }
@@ -42,15 +39,9 @@
   void OnAppStatesChanged(const std::string& app_id,
                           const ArcAppListPrefs::AppInfo& app_info) override;
 
-  // apps::AppRegistryCache::Observer overrides:
-  void OnAppUpdate(const apps::AppUpdate& update) override;
-  void OnAppRegistryCacheWillBeDestroyed(
-      apps::AppRegistryCache* cache) override;
-
  private:
   bool MaybeLaunchApp(const std::string& app_id,
-                      const ArcAppListPrefs::AppInfo& app_info,
-                      apps::mojom::Readiness readiness);
+                      const ArcAppListPrefs::AppInfo& app_info);
 
   // Unowned pointer.
   content::BrowserContext* context_;
@@ -58,7 +49,7 @@
   const std::string app_id_;
   // Optional intent to launch the app. If not set then app is started default
   // way.
-  apps::mojom::IntentPtr launch_intent_;
+  const base::Optional<std::string> launch_intent_;
   // If it is set to true that means app is allowed to launch in deferred mode
   // once it is registered, regardless it is ready or not. Otherwise app is
   // launched when it becomes ready.
@@ -68,7 +59,7 @@
   // Flag indicating that ARC app was launched.
   bool app_launched_ = false;
   // Enum that indicates what type of metric to record to UMA on launch.
-  apps::mojom::LaunchSource launch_source_;
+  arc::UserInteractionType interaction_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcAppLauncher);
 };
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index 8d48462..815abde 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -2124,3 +2124,7 @@
 // Need to add explicit destructor for chromium style checker error:
 // Complex class/struct needs an explicit out-of-line destructor
 ArcAppListPrefs::PackageInfo::~PackageInfo() = default;
+
+ArcAppListPrefs::Observer::~Observer() {
+  // TODO(jamescook): Add CHECK(!IsInObserverList()).
+}
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
index c047af6..16b2ece 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.h
@@ -19,6 +19,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -142,7 +143,7 @@
         permissions;
   };
 
-  class Observer {
+  class Observer : public base::CheckedObserver {
    public:
     // Notifies an observer that new app is registered.
     virtual void OnAppRegistered(const std::string& app_id,
@@ -225,7 +226,7 @@
     virtual void OnArcAppListPrefsDestroyed() {}
 
    protected:
-    virtual ~Observer() {}
+    ~Observer() override;
   };
 
   static ArcAppListPrefs* Create(Profile* profile);
@@ -578,7 +579,7 @@
       app_connection_holder_for_testing_;
 
   // List of observers.
-  base::ObserverList<Observer>::Unchecked observer_list_;
+  base::ObserverList<Observer> observer_list_;
   // Keeps root folder where ARC app icons for different scale factor are
   // stored.
   base::FilePath base_path_;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.cc b/chrome/browser/ui/app_list/arc/arc_app_test.cc
index ab49e33..4090f363 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_test.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_test.cc
@@ -23,13 +23,11 @@
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
-#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/arc/session/arc_session_runner.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_app_instance.h"
 #include "components/arc/test/fake_arc_session.h"
-#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/user_manager/scoped_user_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -231,12 +229,6 @@
 }
 
 void ArcAppTest::TearDown() {
-  if (intent_helper_instance_) {
-    arc_service_manager_->arc_bridge_service()->intent_helper()->CloseInstance(
-        intent_helper_instance_.get());
-    intent_helper_instance_.reset();
-    intent_helper_bridge_.reset();
-  }
   app_instance_.reset();
   arc_play_store_enabled_preference_handler_.reset();
   arc_session_manager_.reset();
@@ -266,17 +258,6 @@
   WaitForInstanceReady(bridge_service->app());
 }
 
-void ArcAppTest::SetUpIntentHelper() {
-  DCHECK(profile_);
-  auto* arc_bridge_service = arc_service_manager_->arc_bridge_service();
-  intent_helper_bridge_ = std::make_unique<arc::ArcIntentHelperBridge>(
-      profile_, arc_bridge_service);
-  intent_helper_instance_ = std::make_unique<arc::FakeIntentHelperInstance>();
-  arc_bridge_service->intent_helper()->SetInstance(
-      intent_helper_instance_.get());
-  WaitForInstanceReady(arc_bridge_service->intent_helper());
-}
-
 const user_manager::User* ArcAppTest::CreateUserAndLogin() {
   const AccountId account_id(AccountId::FromUserEmailGaiaId(
       profile_->GetProfileUserName(), "1234567890"));
diff --git a/chrome/browser/ui/app_list/arc/arc_app_test.h b/chrome/browser/ui/app_list/arc/arc_app_test.h
index 38c0084..553ce36 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_test.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_test.h
@@ -16,12 +16,10 @@
 namespace mojom {
 class AppInfo;
 }
-class ArcIntentHelperBridge;
 class ArcPlayStoreEnabledPreferenceHandler;
 class ArcServiceManager;
 class ArcSessionManager;
 class FakeAppInstance;
-class FakeIntentHelperInstance;
 }  // namespace arc
 
 namespace chromeos {
@@ -49,8 +47,6 @@
   void StopArcInstance();
   void RestartArcInstance();
 
-  void SetUpIntentHelper();
-
   static std::string GetAppId(const arc::mojom::AppInfo& app_info);
   static std::string GetAppId(const arc::mojom::ShortcutInfo& shortcut);
 
@@ -86,10 +82,6 @@
 
   arc::FakeAppInstance* app_instance() { return app_instance_.get(); }
 
-  arc::FakeIntentHelperInstance* intent_helper_instance() {
-    return intent_helper_instance_.get();
-  }
-
   ArcAppListPrefs* arc_app_list_prefs() { return arc_app_list_pref_; }
 
   arc::ArcSessionManager* arc_session_manager() {
@@ -135,8 +127,6 @@
   std::unique_ptr<arc::ArcPlayStoreEnabledPreferenceHandler>
       arc_play_store_enabled_preference_handler_;
   std::unique_ptr<arc::FakeAppInstance> app_instance_;
-  std::unique_ptr<arc::ArcIntentHelperBridge> intent_helper_bridge_;
-  std::unique_ptr<arc::FakeIntentHelperInstance> intent_helper_instance_;
 
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
   std::vector<arc::mojom::AppInfo> fake_apps_;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index 937958c..4948156f 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -76,10 +76,8 @@
 #include "components/arc/mojom/app.mojom.h"
 #include "components/arc/mojom/compatibility_mode.mojom.h"
 #include "components/arc/test/fake_app_instance.h"
-#include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
 #include "components/services/app_service/public/cpp/app_update.h"
-#include "components/services/app_service/public/cpp/intent_util.h"
 #include "components/services/app_service/public/cpp/stub_icon_loader.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "components/sync/driver/profile_sync_service.h"
@@ -444,7 +442,6 @@
 
     OnBeforeArcTestSetup();
     arc_test_.SetUp(profile_.get());
-    arc_test_.SetUpIntentHelper();
 
     web_app::TestWebAppProvider::Get(profile_.get())->Start();
     CreateBuilder();
@@ -810,10 +807,6 @@
 
   arc::FakeAppInstance* app_instance() { return arc_test_.app_instance(); }
 
-  arc::FakeIntentHelperInstance* intent_helper_instance() {
-    return arc_test_.intent_helper_instance();
-  }
-
   FakeAppListModelUpdater* model_updater() { return model_updater_.get(); }
 
  private:
@@ -883,6 +876,9 @@
   }
 
   void TearDown() override {
+    // Clean up any observers added in StartApp(). This is a no-op if we didn't
+    // add an observer.
+    arc_test()->arc_app_list_prefs()->RemoveObserver(this);
     scoped_supported_scale_factors_.reset();
     ArcAppModelBuilderRecreate::TearDown();
   }
@@ -1273,8 +1269,9 @@
 
     std::string error;
     arc_support_host_ = extensions::Extension::Create(
-        base::FilePath(), extensions::Manifest::UNPACKED, manifest,
-        extensions::Extension::NO_FLAGS, arc::kPlayStoreAppId, &error);
+        base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
+        manifest, extensions::Extension::NO_FLAGS, arc::kPlayStoreAppId,
+        &error);
 
     extensions::ExtensionService* extension_service =
         extensions::ExtensionSystem::Get(profile_.get())->extension_service();
@@ -2996,63 +2993,43 @@
   const std::string id2 = ArcAppTest::GetAppId(app2);
   const std::string id3 = ArcAppTest::GetAppId(app3);
 
-  {
-    ArcAppLauncher launcher1(profile(), id1, nullptr, false,
-                             display::kInvalidDisplayId,
-                             apps::mojom::LaunchSource::kFromChromeInternal);
-    EXPECT_FALSE(launcher1.app_launched());
-    EXPECT_TRUE(prefs->HasObserver(&launcher1));
+  ArcAppLauncher launcher1(profile(), id1, base::Optional<std::string>(), false,
+                           display::kInvalidDisplayId,
+                           arc::UserInteractionType::NOT_USER_INITIATED);
+  EXPECT_FALSE(launcher1.app_launched());
+  EXPECT_TRUE(prefs->HasObserver(&launcher1));
 
-    ArcAppLauncher launcher3(profile(), id3, nullptr, false,
-                             display::kInvalidDisplayId,
-                             apps::mojom::LaunchSource::kFromChromeInternal);
-    EXPECT_FALSE(launcher1.app_launched());
-    EXPECT_TRUE(prefs->HasObserver(&launcher1));
-    EXPECT_FALSE(launcher3.app_launched());
-    EXPECT_TRUE(prefs->HasObserver(&launcher3));
+  ArcAppLauncher launcher3(profile(), id3, base::Optional<std::string>(), false,
+                           display::kInvalidDisplayId,
+                           arc::UserInteractionType::NOT_USER_INITIATED);
+  EXPECT_FALSE(launcher1.app_launched());
+  EXPECT_TRUE(prefs->HasObserver(&launcher1));
+  EXPECT_FALSE(launcher3.app_launched());
+  EXPECT_TRUE(prefs->HasObserver(&launcher3));
 
-    EXPECT_EQ(0u, intent_helper_instance()->handled_intents().size());
+  EXPECT_EQ(0u, app_instance()->launch_requests().size());
 
-    std::vector<arc::mojom::AppInfo> apps(fake_apps().begin(),
-                                          fake_apps().begin() + 2);
-    SendRefreshAppList(apps);
+  std::vector<arc::mojom::AppInfo> apps(fake_apps().begin(),
+                                        fake_apps().begin() + 2);
+  SendRefreshAppList(apps);
 
-    EXPECT_TRUE(launcher1.app_launched());
-    EXPECT_FALSE(prefs->HasObserver(&launcher1));
-    EXPECT_TRUE(prefs->HasObserver(&launcher3));
-    EXPECT_FALSE(launcher3.app_launched());
-  }
-
+  EXPECT_TRUE(launcher1.app_launched());
   ASSERT_EQ(1u, app_instance()->launch_requests().size());
   EXPECT_TRUE(app_instance()->launch_requests()[0]->IsForApp(app1));
+  EXPECT_FALSE(launcher3.app_launched());
+  EXPECT_FALSE(prefs->HasObserver(&launcher1));
+  EXPECT_TRUE(prefs->HasObserver(&launcher3));
 
-  {
-    auto launch_intent2 = apps_util::CreateIntentForActivity(
-        app2.activity, arc::kInitialStartParam);
-    ArcAppLauncher launcher2(profile(), id2, std::move(launch_intent2), false,
-                             display::kInvalidDisplayId,
-                             apps::mojom::LaunchSource::kFromChromeInternal);
-    EXPECT_TRUE(launcher2.app_launched());
-    EXPECT_FALSE(prefs->HasObserver(&launcher2));
-  }
-
-  FlushMojoCallsForAppService();
-  ASSERT_EQ(1u, intent_helper_instance()->handled_intents().size());
-
-  auto& intent = intent_helper_instance()->handled_intents()[0].intent;
-  ASSERT_TRUE(intent);
-  ASSERT_TRUE(intent->extras.has_value());
-  ASSERT_EQ(1u, intent->extras.value().size());
-  auto it = intent->extras.value().begin();
-  EXPECT_EQ(arc::kInitialStartParam, it->second);
-
-  ASSERT_TRUE(intent_helper_instance()->handled_intents()[0].activity);
-  ASSERT_TRUE(intent_helper_instance()
-                  ->handled_intents()[0]
-                  .activity->activity_name.has_value());
-  EXPECT_EQ(app2.activity, intent_helper_instance()
-                               ->handled_intents()[0]
-                               .activity->activity_name.value());
+  const std::string launch_intent2 = arc::GetLaunchIntent(
+      app2.package_name, app2.activity, std::vector<std::string>());
+  ArcAppLauncher launcher2(profile(), id2, launch_intent2, false,
+                           display::kInvalidDisplayId,
+                           arc::UserInteractionType::NOT_USER_INITIATED);
+  EXPECT_TRUE(launcher2.app_launched());
+  EXPECT_FALSE(prefs->HasObserver(&launcher2));
+  EXPECT_EQ(1u, app_instance()->launch_requests().size());
+  ASSERT_EQ(1u, app_instance()->launch_intents().size());
+  EXPECT_EQ(app_instance()->launch_intents()[0], launch_intent2);
 }
 
 // Suspended app cannot be triggered from app launcher.
@@ -3064,9 +3041,9 @@
   app.suspended = true;
   const std::string app_id = ArcAppTest::GetAppId(app);
 
-  ArcAppLauncher launcher(profile(), app_id, nullptr, false,
-                          display::kInvalidDisplayId,
-                          apps::mojom::LaunchSource::kFromChromeInternal);
+  ArcAppLauncher launcher(profile(), app_id, base::Optional<std::string>(),
+                          false, display::kInvalidDisplayId,
+                          arc::UserInteractionType::NOT_USER_INITIATED);
   EXPECT_FALSE(launcher.app_launched());
 
   // Register app, however it is suspended.
@@ -3463,26 +3440,23 @@
   const std::string id2 = ArcAppTest::GetAppId(app2);
 
   // Launch when app is registered and ready.
-  ArcAppLauncher launcher1(profile(), id1, nullptr, false,
+  ArcAppLauncher launcher1(profile(), id1, base::Optional<std::string>(), false,
                            display::kInvalidDisplayId,
-                           apps::mojom::LaunchSource::kFromChromeInternal);
-
+                           arc::UserInteractionType::NOT_USER_INITIATED);
   // Launch when app is registered.
-  ArcAppLauncher launcher2(profile(), id2, nullptr, true,
+  ArcAppLauncher launcher2(profile(), id2, base::Optional<std::string>(), true,
                            display::kInvalidDisplayId,
-                           apps::mojom::LaunchSource::kFromChromeInternal);
+                           arc::UserInteractionType::NOT_USER_INITIATED);
 
   EXPECT_FALSE(launcher1.app_launched());
 
   arc_test()->WaitForDefaultApps();
-  FlushMojoCallsForAppService();
 
   // Only second app is expected to be launched.
   EXPECT_FALSE(launcher1.app_launched());
   EXPECT_TRUE(launcher2.app_launched());
 
   SendRefreshAppList(fake_default_apps());
-
   // Default apps are ready now and it is expected that first app was launched
   // now.
   EXPECT_TRUE(launcher1.app_launched());
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index bd55b1f..7975eb2 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -221,7 +221,7 @@
 }  // namespace
 
 // Package names, kept in sorted order.
-const char kInitialStartParam[] = "initialStart";
+const char kInitialStartParam[] = "S.org.chromium.arc.start_type=initialStart";
 const char kRequestStartTimeParamTemplate[] =
     "S.org.chromium.arc.request.start=%" PRId64;
 const char kPlayStoreActivity[] = "com.android.vending.AssetBrowserActivity";
diff --git a/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.cc b/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.cc
index 69485cb..c327a86f 100644
--- a/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.cc
+++ b/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.cc
@@ -159,4 +159,8 @@
 
 ArcVpnProviderManager::ArcVpnProvider::~ArcVpnProvider() = default;
 
+ArcVpnProviderManager::Observer::~Observer() {
+  // TODO(jamescook): Add CHECK(!IsInObserverList()).
+}
+
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.h b/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.h
index 3c458ec..f9abaa4 100644
--- a/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.h
+++ b/chrome/browser/ui/app_list/arc/arc_vpn_provider_manager.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -32,7 +33,7 @@
     const base::Time last_launch_time;
   };
 
-  class Observer {
+  class Observer : public base::CheckedObserver {
    public:
     // Notifies initial refresh of Arc VPN providers.
     virtual void OnArcVpnProvidersRefreshed(
@@ -45,7 +46,7 @@
     virtual void OnArcVpnProviderUpdated(ArcVpnProvider* arc_vpn_provider) {}
 
    protected:
-    virtual ~Observer() {}
+    ~Observer() override;
   };
 
   static ArcVpnProviderManager* Get(content::BrowserContext* context);
@@ -77,7 +78,7 @@
   ArcAppListPrefs* const arc_app_list_prefs_;
 
   // List of observers.
-  base::ObserverList<Observer>::Unchecked observer_list_;
+  base::ObserverList<Observer> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcVpnProviderManager);
 };
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index 18a8025..0b20f2b 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -96,9 +96,9 @@
 }
 
 void ChromeAppListModelUpdater::RemoveUninstalledItem(const std::string& id) {
+  RemoveChromeItem(id);
   if (app_list_controller_)
     app_list_controller_->RemoveUninstalledItem(id);
-  RemoveChromeItem(id);
 }
 
 void ChromeAppListModelUpdater::MoveItemToFolder(const std::string& id,
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
index 6cd5caf0..753cf6b 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_icon_image_loader_unittest.cc
@@ -113,8 +113,8 @@
   manifest.SetKey(extensions::manifest_keys::kName,
                   base::Value("TestExtension"));
   return extensions::Extension::Create(
-      base::FilePath(), extensions::Manifest::UNPACKED, manifest,
-      extensions::Extension::NO_FLAGS, extension_id, &error);
+      base::FilePath(), extensions::mojom::ManifestLocation::kUnpacked,
+      manifest, extensions::Extension::NO_FLAGS, extension_id, &error);
 }
 
 // Returns true if icon image of |result_image| equals to |expected_image|.
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
index eeb9652..1f77c6e 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.cc
@@ -12,11 +12,11 @@
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/apps/app_service/menu_util.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
 #include "chrome/browser/ash/crosapi/browser_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_manager_factory.h"
 #include "chrome/browser/ash/plugin_vm/plugin_vm_util.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcuts_menu_builder.h"
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
 #include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
 #include "chrome/browser/chromeos/crostini/crostini_terminal.h"
diff --git a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.h b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.h
index a9817f7..b1ef2fd7 100644
--- a/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.h
+++ b/chrome/browser/ui/ash/launcher/app_service/app_service_shelf_context_menu.h
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/chromeos/arc/app_shortcuts/arc_app_shortcut_item.h"
+#include "chrome/browser/ash/arc/app_shortcuts/arc_app_shortcut_item.h"
 #include "chrome/browser/ui/ash/launcher/shelf_context_menu.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "extensions/common/constants.h"
diff --git a/chrome/browser/ui/ash/launcher/app_service/exo_app_type_resolver.cc b/chrome/browser/ui/ash/launcher/app_service/exo_app_type_resolver.cc
index ce30427..6978128f 100644
--- a/chrome/browser/ui/ash/launcher/app_service/exo_app_type_resolver.cc
+++ b/chrome/browser/ui/ash/launcher/app_service/exo_app_type_resolver.cc
@@ -55,7 +55,12 @@
   out_properties_container.SetProperty(aura::client::kAppType,
                                        static_cast<int>(ash::AppType::ARC_APP));
   out_properties_container.SetProperty(full_restore::kWindowIdKey, task_id);
-  out_properties_container.SetProperty(
-      full_restore::kRestoreWindowIdKey,
-      full_restore::GetArcRestoreWindowId(task_id));
+  int32_t restore_window_id = full_restore::GetArcRestoreWindowId(task_id);
+  out_properties_container.SetProperty(full_restore::kRestoreWindowIdKey,
+                                       restore_window_id);
+
+  if (restore_window_id == full_restore::kParentToHiddenContainer) {
+    out_properties_container.SetProperty(
+        full_restore::kParentToHiddenContainerKey, true);
+  }
 }
diff --git a/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
index 28af332..6b280be6 100644
--- a/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
@@ -36,9 +36,10 @@
     std::unique_ptr<ArcAppLauncher> playstore_launcher =
         std::make_unique<ArcAppLauncher>(
             ChromeLauncherController::instance()->profile(),
-            arc::kPlayStoreAppId, nullptr /* launch_intent */,
+            arc::kPlayStoreAppId,
+            base::Optional<std::string>() /* launch_intent */,
             true /* deferred_launch_allowed */, display_id,
-            apps::mojom::LaunchSource::kFromShelf);
+            arc::UserInteractionType::APP_STARTED_FROM_SHELF);
     // ArcAppLauncher may launch Play Store in case it exists already. In this
     // case this instance of ArcPlaystoreShortcutLauncherItemController may be
     // deleted. If Play Store does not exist at this moment, then let
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index a9fe12f9..98dc64a7 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -158,6 +158,7 @@
 using extensions::Extension;
 using extensions::Manifest;
 using extensions::UnloadedExtensionReason;
+using extensions::mojom::ManifestLocation;
 
 namespace {
 constexpr char kOfflineGmailUrl[] = "https://mail.google.com/mail/mu/u";
@@ -412,33 +413,33 @@
     StartAppSyncService(app_list_syncable_service_->GetAllSyncDataForTesting());
 
     std::string error;
-    extension_chrome_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                          manifest, Extension::NO_FLAGS,
-                                          extension_misc::kChromeAppId, &error);
-    extension1_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &error);
-    extension2_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", &error);
-    extension5_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "cccccccccccccccccccccccccccccccc", &error);
-    extension6_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "dddddddddddddddddddddddddddddddd", &error);
-    extension7_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", &error);
-    extension8_ = Extension::Create(base::FilePath(), Manifest::UNPACKED,
-                                    manifest, Extension::NO_FLAGS,
-                                    "ffffffffffffffffffffffffffffffff", &error);
+    extension_chrome_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, extension_misc::kChromeAppId, &error);
+    extension1_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", &error);
+    extension2_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", &error);
+    extension5_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "cccccccccccccccccccccccccccccccc", &error);
+    extension6_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "dddddddddddddddddddddddddddddddd", &error);
+    extension7_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", &error);
+    extension8_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, "ffffffffffffffffffffffffffffffff", &error);
     extension_platform_app_ = Extension::Create(
-        base::FilePath(), Manifest::UNPACKED, manifest_platform_app,
+        base::FilePath(), ManifestLocation::kUnpacked, manifest_platform_app,
         Extension::NO_FLAGS, "gggggggggggggggggggggggggggggggg", &error);
-    arc_support_host_ =
-        Extension::Create(base::FilePath(), Manifest::UNPACKED, manifest,
-                          Extension::NO_FLAGS, arc::kPlayStoreAppId, &error);
+    arc_support_host_ = Extension::Create(
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, arc::kPlayStoreAppId, &error);
     extension_service_->AddExtension(extension_chrome_.get());
 
     // Fake Gmail app.
@@ -456,22 +457,22 @@
     manifest_gmail.Set(extensions::manifest_keys::kWebURLs, std::move(list));
 
     extension_gmail_app_ = Extension::Create(
-        base::FilePath(), Manifest::UNPACKED, manifest_gmail,
+        base::FilePath(), ManifestLocation::kUnpacked, manifest_gmail,
         Extension::NO_FLAGS, extension_misc::kGmailAppId, &error);
     // Fake Google Doc app.
     extension_doc_app_ = Extension::Create(
-        base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
-        extension_misc::kGoogleDocAppId, &error);
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, extension_misc::kGoogleDocAppId, &error);
 
     // Fake Youtube app.
     extension_youtube_app_ = Extension::Create(
-        base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
-        extension_misc::kYoutubeAppId, &error);
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, extension_misc::kYoutubeAppId, &error);
 
     // Fake File Manager app.
     extension_files_app_ = Extension::Create(
-        base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
-        extension_misc::kFilesManagerAppId, &error);
+        base::FilePath(), ManifestLocation::kUnpacked, manifest,
+        Extension::NO_FLAGS, extension_misc::kFilesManagerAppId, &error);
 
     MaybeStartWebAppProvider();
   }
@@ -1176,8 +1177,8 @@
       manifest.SetString(extensions::manifest_keys::kName,
                          extension_id_name.second);
       scoped_refptr<Extension> extension = Extension::Create(
-          base::FilePath(), Manifest::UNPACKED, manifest, Extension::NO_FLAGS,
-          extension_id_name.first, &error);
+          base::FilePath(), ManifestLocation::kUnpacked, manifest,
+          Extension::NO_FLAGS, extension_id_name.first, &error);
       extension_service_->AddExtension(extension.get());
       extra_extensions_.emplace_back(extension);
     }
@@ -4480,7 +4481,6 @@
       model_->GetShelfItemDelegate(ash::ShelfID(arc::kPlayStoreAppId));
   EXPECT_TRUE(item_delegate);
   SelectItem(item_delegate);
-  app_service_test().FlushMojoCalls();
   EXPECT_TRUE(launcher_controller_->IsAppPinned(arc::kPlayStoreAppId));
   EXPECT_TRUE(launcher_controller_->GetShelfSpinnerController()->HasApp(
       arc::kPlayStoreAppId));
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index 561f31b..603019b2 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -15,10 +15,10 @@
 #include "ui/accessibility/aura/aura_window_properties.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_action_handler_base.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_event.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_source_checker.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
@@ -303,7 +303,8 @@
   // If the window has a child AX tree ID, forward the action to the
   // associated AXActionHandlerBase.
   if (child_ax_tree_id != ui::AXTreeIDUnknown()) {
-    ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
+    ui::AXActionHandlerRegistry* registry =
+        ui::AXActionHandlerRegistry::GetInstance();
     ui::AXActionHandlerBase* action_handler =
         registry->GetActionHandler(child_ax_tree_id);
     CHECK(action_handler);
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
index d20e983..957c732 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -61,8 +61,8 @@
 
 // A helper to retrieve an ax tree id given a RenderFrameHost.
 ui::AXTreeID GetAXTreeIDFromRenderFrameHost(content::RenderFrameHost* rfh) {
-  auto* registry = ui::AXTreeIDRegistry::GetInstance();
-  return registry->GetAXTreeID(ui::AXTreeIDRegistry::FrameID(
+  auto* registry = ui::AXActionHandlerRegistry::GetInstance();
+  return registry->GetAXTreeID(ui::AXActionHandlerRegistry::FrameID(
       rfh->GetProcess()->GetID(), rfh->GetRoutingID()));
 }
 
@@ -424,8 +424,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest,
-                       AXTreeIDRegistryUpdates) {
-  ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
+                       AXActionHandlerRegistryUpdates) {
+  ui::AXActionHandlerRegistry* registry =
+      ui::AXActionHandlerRegistry::GetInstance();
   AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
   ui::AXTreeID tree_id = manager->ax_tree_id();
 
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
index aa15fbd..42c2c7b 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -268,26 +268,6 @@
   CheckBubbleIsNotPresent(third_browser, false, false);
 }
 
-void ExtensionMessageBubbleBrowserTest::TestControlledNewTabPageBubbleShown(
-    bool click_learn_more) {
-  ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
-                                          .AppendASCII("override")
-                                          .AppendASCII("newtab")));
-  CheckBubbleIsNotPresent(browser(), false, false);
-  EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  chrome::NewTab(browser());
-  EXPECT_EQ(2, browser()->tab_strip_model()->count());
-  base::RunLoop().RunUntilIdle();
-  CheckBubble(browser(), ANCHOR_BROWSER_ACTION, false);
-  if (click_learn_more) {
-    ClickLearnMoreButton(browser());
-    EXPECT_EQ(3, browser()->tab_strip_model()->count());
-  } else {
-    CloseBubble(browser());
-    EXPECT_EQ(2, browser()->tab_strip_model()->count());
-  }
-}
-
 void ExtensionMessageBubbleBrowserTest::TestControlledHomeBubbleShown() {
   browser()->profile()->GetPrefs()->SetBoolean(prefs::kShowHomeButton, true);
 
diff --git a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc
index f6ad4d8..5eccaed 100644
--- a/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc
+++ b/chrome/browser/ui/extensions/settings_api_bubble_helpers.cc
@@ -8,9 +8,10 @@
 
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
-#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
+#include "chrome/browser/extensions/extension_web_ui.h"
 #include "chrome/browser/extensions/settings_api_bubble_delegate.h"
 #include "chrome/browser/extensions/settings_api_helpers.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -22,6 +23,8 @@
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
 #include "chrome/common/url_constants.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "content/public/browser/browser_url_handler.h"
 #include "content/public/browser/navigation_entry.h"
 #include "extensions/common/constants.h"
@@ -38,6 +41,24 @@
 bool g_ntp_post_install_ui_enabled = false;
 #endif
 
+// Whether to acknowledge existing extensions overriding the NTP for the active
+// profile. Active on MacOS to rollout the NTP bubble without prompting for
+// previously-installed extensions.
+// TODO(devlin): This has been rolled out on Mac for awhile; we can flip this to
+// false (and keep the logic around for when/if we decide to expand the warning
+// treatment to Linux).
+bool g_acknowledge_existing_ntp_extensions =
+#if defined(OS_MAC)
+    true;
+#else
+    false;
+#endif
+
+// The name of the preference indicating whether existing NTP extensions have
+// been automatically acknowledged.
+const char kDidAcknowledgeExistingNtpExtensions[] =
+    "ack_existing_ntp_extensions";
+
 #if defined(OS_WIN) || defined(OS_MAC)
 void ShowSettingsApiBubble(SettingsApiOverrideType type,
                            Browser* browser) {
@@ -61,10 +82,47 @@
 
 }  // namespace
 
+// Whether a given ntp-overriding extension has been acknowledged by the user.
+// The terse key value is because the pref has migrated between code layers.
+const char kNtpOverridingExtensionAcknowledged[] = "ack_ntp_bubble";
+
 void SetNtpPostInstallUiEnabledForTesting(bool enabled) {
   g_ntp_post_install_ui_enabled = enabled;
 }
 
+base::AutoReset<bool> SetAcknowledgeExistingNtpExtensionsForTesting(
+    bool should_acknowledge) {
+  return base::AutoReset<bool>(&g_acknowledge_existing_ntp_extensions,
+                               should_acknowledge);
+}
+
+void AcknowledgePreExistingNtpExtensions(Profile* profile) {
+  DCHECK(g_acknowledge_existing_ntp_extensions);
+
+  ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
+  PrefService* profile_prefs = profile->GetPrefs();
+  // Only acknowledge existing extensions once per profile.
+  if (profile_prefs->GetBoolean(kDidAcknowledgeExistingNtpExtensions))
+    return;
+
+  profile_prefs->SetBoolean(kDidAcknowledgeExistingNtpExtensions, true);
+  ExtensionPrefs* prefs = ExtensionPrefs::Get(profile);
+  for (const auto& extension : registry->enabled_extensions()) {
+    const URLOverrides::URLOverrideMap& overrides =
+        URLOverrides::GetChromeURLOverrides(extension.get());
+    if (overrides.find(chrome::kChromeUINewTabHost) != overrides.end()) {
+      prefs->UpdateExtensionPref(extension->id(),
+                                 kNtpOverridingExtensionAcknowledged,
+                                 std::make_unique<base::Value>(true));
+    }
+  }
+}
+
+void RegisterSettingsOverriddenUiPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(kDidAcknowledgeExistingNtpExtensions, false,
+                                PrefRegistry::NO_REGISTRATION_FLAGS);
+}
+
 void MaybeShowExtensionControlledHomeNotification(Browser* browser) {
 #if defined(OS_WIN) || defined(OS_MAC)
   ShowSettingsApiBubble(BUBBLE_TYPE_HOME_PAGE, browser);
@@ -110,8 +168,8 @@
     return;
 
   // Acknowledge existing extensions if necessary.
-  NtpOverriddenBubbleDelegate::MaybeAcknowledgeExistingNtpExtensions(
-      browser->profile());
+  if (g_acknowledge_existing_ntp_extensions)
+    AcknowledgePreExistingNtpExtensions(browser->profile());
 
   // Jump through a series of hoops to see if the web contents is pointing to
   // an extension-controlled NTP.
@@ -153,18 +211,6 @@
     chrome::ShowExtensionSettingsOverriddenDialog(std::move(dialog), browser);
     return;
   }
-
-  std::unique_ptr<ExtensionMessageBubbleController> ntp_overridden_bubble(
-      new ExtensionMessageBubbleController(
-          new NtpOverriddenBubbleDelegate(profile), browser));
-  if (!ntp_overridden_bubble->ShouldShow())
-    return;
-
-  ntp_overridden_bubble->SetIsActiveBubble();
-  std::unique_ptr<ToolbarActionsBarBubbleDelegate> bridge(
-      new ExtensionMessageBubbleBridge(std::move(ntp_overridden_bubble)));
-  browser->window()->GetExtensionsContainer()->ShowToolbarActionBubbleAsync(
-      std::move(bridge));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/ui/extensions/settings_api_bubble_helpers.h b/chrome/browser/ui/extensions/settings_api_bubble_helpers.h
index 0d29533..547df7f 100644
--- a/chrome/browser/ui/extensions/settings_api_bubble_helpers.h
+++ b/chrome/browser/ui/extensions/settings_api_bubble_helpers.h
@@ -5,9 +5,12 @@
 #ifndef CHROME_BROWSER_UI_EXTENSIONS_SETTINGS_API_BUBBLE_HELPERS_H_
 #define CHROME_BROWSER_UI_EXTENSIONS_SETTINGS_API_BUBBLE_HELPERS_H_
 
+#include "base/auto_reset.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 
 class Browser;
+class PrefRegistrySimple;
+class Profile;
 
 namespace content {
 class WebContents;
@@ -15,10 +18,27 @@
 
 namespace extensions {
 
+extern const char kNtpOverridingExtensionAcknowledged[];
+
 // Sets whether the NTP post-install UI is enabled for testing purposes.
 // TODO(devlin): This would be cooler as a base::AutoReset<>.
 void SetNtpPostInstallUiEnabledForTesting(bool enabled);
 
+// Testing-only method to configure if existing NTP extensions are
+// auto-acknowledged.
+base::AutoReset<bool> SetAcknowledgeExistingNtpExtensionsForTesting(
+    bool should_acknowledge);
+
+// Registers prefs related to the settings overridden UI.
+void RegisterSettingsOverriddenUiPrefs(PrefRegistrySimple* registry);
+
+// Iterates over existing NTP-overriding extensions installed in the given
+// `profile` and marks them as acknowledged. Stores a preference indicating
+// the action was completed. Subsequent calls will *not* acknowledge more
+// extensions. This is needed to avoid prompting users with existing
+// extensions when we expand the warning to new platforms.
+void AcknowledgePreExistingNtpExtensions(Profile* profile);
+
 // Shows a bubble notifying the user that the homepage is controlled by an
 // extension. This bubble is shown only on the first use of the Home button
 // after the controlling extension takes effect.
diff --git a/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc b/chrome/browser/ui/extensions/settings_api_bubble_helpers_unittest.cc
similarity index 60%
rename from chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc
rename to chrome/browser/ui/extensions/settings_api_bubble_helpers_unittest.cc
index 70a2e0eb..b304aae9 100644
--- a/chrome/browser/extensions/ntp_overridden_bubble_delegate_unittest.cc
+++ b/chrome/browser/ui/extensions/settings_api_bubble_helpers_unittest.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/extensions/ntp_overridden_bubble_delegate.h"
+#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 
 #include <memory>
 
@@ -41,11 +41,11 @@
 
 }  // namespace
 
-using NtpOverriddenBubbleDelegateTest = ExtensionServiceTestBase;
+using SettingsApiBubbleHelpersUnitTest = ExtensionServiceTestBase;
 
-TEST_F(NtpOverriddenBubbleDelegateTest, TestAcknowledgeExistingExtensions) {
-  NtpOverriddenBubbleDelegate::set_acknowledge_existing_extensions_for_testing(
-      true);
+TEST_F(SettingsApiBubbleHelpersUnitTest, TestAcknowledgeExistingExtensions) {
+  base::AutoReset<bool> ack_existing =
+      SetAcknowledgeExistingNtpExtensionsForTesting(true);
 
   InitializeEmptyExtensionService();
   ExtensionWebUIOverrideRegistrar::GetFactoryInstance()->SetTestingFactory(
@@ -58,37 +58,33 @@
   scoped_refptr<const Extension> first = GetNtpExtension("first");
   service()->AddExtension(first.get());
 
-  auto include_extension = [this](const Extension* extension) {
-    auto ntp_delegate =
-        std::make_unique<NtpOverriddenBubbleDelegate>(profile());
-    return ntp_delegate->ShouldIncludeExtension(extension);
+  auto is_acknowledged = [this](const ExtensionId& id) {
+    bool is_acked = false;
+    return ExtensionPrefs::Get(profile())->ReadPrefAsBoolean(
+               id, kNtpOverridingExtensionAcknowledged, &is_acked) &&
+           is_acked;
   };
-  // By default, we should warn about an extension overriding the NTP.
-  EXPECT_TRUE(include_extension(first.get()));
+  // By default, the extension should not be acknowledged.
+  EXPECT_FALSE(is_acknowledged(first->id()));
 
-  // Acknowledge existing extensions. Now, |first| should be acknowledged and
-  // shouldn't be included in the bubble warning.
-  NtpOverriddenBubbleDelegate::MaybeAcknowledgeExistingNtpExtensions(profile());
-  EXPECT_FALSE(include_extension(first.get()));
+  // Acknowledge existing extensions. Now, `first` should be acknowledged.
+  AcknowledgePreExistingNtpExtensions(profile());
+  EXPECT_TRUE(is_acknowledged(first->id()));
 
-  // Install a second NTP-overriding extension. As before, we should include the
-  // extension.
+  // Install a second NTP-overriding extension. The new extension should not be
+  // acknowledged.
   scoped_refptr<const Extension> second = GetNtpExtension("second");
   service()->AddExtension(second.get());
-  EXPECT_TRUE(include_extension(second.get()));
+  EXPECT_FALSE(is_acknowledged(second->id()));
 
   // Try acknowledging existing extensions. Since we already did this once for
-  // this profile, this should have no effect, and we should still warn about
-  // the second extension.
-  NtpOverriddenBubbleDelegate::MaybeAcknowledgeExistingNtpExtensions(profile());
-  EXPECT_TRUE(include_extension(second.get()));
+  // this profile, this should have no effect, and we should still consider the
+  // second extension unacknowledged.
+  AcknowledgePreExistingNtpExtensions(profile());
+  EXPECT_FALSE(is_acknowledged(second->id()));
 
-  // We should still not warn about the first.
-  EXPECT_FALSE(include_extension(first.get()));
-
-  // Clean up.
-  NtpOverriddenBubbleDelegate::set_acknowledge_existing_extensions_for_testing(
-      false);
+  // But the first should still be acknowledged.
+  EXPECT_TRUE(is_acknowledged(first->id()));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/ui/extensions/settings_overridden_params_providers.cc b/chrome/browser/ui/extensions/settings_overridden_params_providers.cc
index c69d007..7e65f98 100644
--- a/chrome/browser/ui/extensions/settings_overridden_params_providers.cc
+++ b/chrome/browser/ui/extensions/settings_overridden_params_providers.cc
@@ -8,11 +8,11 @@
 #include "build/branding_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/extensions/extension_web_ui.h"
-#include "chrome/browser/extensions/ntp_overridden_bubble_delegate.h"
 #include "chrome/browser/extensions/settings_api_bubble_delegate.h"
 #include "chrome/browser/extensions/settings_api_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 #include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
@@ -146,11 +146,9 @@
   if (!extension)
     return base::nullopt;
 
-  // We deliberately re-use the same preference that the bubble UI uses. This
-  // way, users won't see the bubble or dialog UI if they've already
-  // acknowledged either version.
-  const char* preference_name =
-      extensions::NtpOverriddenBubbleDelegate::kNtpBubbleAcknowledged;
+  // This preference tracks whether users have acknowledged the extension's
+  // control, so that they are not warned twice about the same extension.
+  const char* preference_name = extensions::kNtpOverridingExtensionAcknowledged;
 
   std::vector<GURL> possible_rewrites =
       content::BrowserURLHandler::GetInstance()->GetPossibleRewrites(ntp_url,
diff --git a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
index 74384db..5c471a43c 100644
--- a/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
+++ b/chrome/browser/ui/sync/profile_signin_confirmation_helper_unittest.cc
@@ -104,7 +104,7 @@
 static scoped_refptr<extensions::Extension> CreateExtension(
     const std::string& name,
     const std::string& id,
-    extensions::Manifest::Location location) {
+    extensions::mojom::ManifestLocation location) {
   base::DictionaryValue manifest;
   manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0");
   manifest.SetInteger(extensions::manifest_keys::kManifestVersion, 2);
@@ -214,17 +214,16 @@
   // Profile is new but has synced extensions (The web store doesn't count).
   profile_->SetIsNewProfile(true);
   scoped_refptr<extensions::Extension> webstore =
-      CreateExtension("web store",
-                      extensions::kWebStoreAppId,
-                      extensions::Manifest::COMPONENT);
+      CreateExtension("web store", extensions::kWebStoreAppId,
+                      extensions::mojom::ManifestLocation::kComponent);
   extensions::ExtensionPrefs::Get(profile_.get())
       ->AddGrantedPermissions(webstore->id(), extensions::PermissionSet());
   extensions->AddExtension(webstore.get());
   EXPECT_FALSE(GetCallbackResult(
       base::BindOnce(&ui::CheckShouldPromptForNewProfile, profile_.get())));
 
-  scoped_refptr<extensions::Extension> extension =
-      CreateExtension("foo", std::string(), extensions::Manifest::INTERNAL);
+  scoped_refptr<extensions::Extension> extension = CreateExtension(
+      "foo", std::string(), extensions::mojom::ManifestLocation::kInternal);
   extensions::ExtensionPrefs::Get(profile_.get())
       ->AddGrantedPermissions(extension->id(), extensions::PermissionSet());
   extensions->AddExtension(extension.get());
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index ac6f0e0..817e44d4 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -125,8 +125,9 @@
     if (!host || host->GetView()->IsShowing())
       return;
     observation_.Observe(host);
-    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("ui,latency",
-                                      "TabSwitchVisibilityRequest", this);
+    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("ui,latency",
+                                      "TabSwitchVisibilityRequest", this,
+                                      "render_widget_host", host);
   }
   ~RenderWidgetHostVisibilityTracker() final = default;
   RenderWidgetHostVisibilityTracker(const RenderWidgetHostVisibilityTracker&) =
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
index 180167b3..c32e8027 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
@@ -89,21 +89,6 @@
   ~FullSizeBubbleFrameView() override = default;
 
  private:
-  // Overridden from views::ViewTargeterDelegate:
-  bool DoesIntersectRect(const View* target,
-                         const gfx::Rect& rect) const override {
-    // Make sure click events can still reach the close button, even if the
-    // ClientView overlaps it.
-    // NOTE: |rect| is in the mirrored coordinate space, so we must use the
-    // close button's mirrored bounds to correctly target the close button when
-    // in RTL mode.
-    if (IsCloseButtonVisible() &&
-        GetCloseButtonMirroredBounds().Intersects(rect)) {
-      return true;
-    }
-    return views::BubbleFrameView::DoesIntersectRect(target, rect);
-  }
-
   // Overridden from views::BubbleFrameView:
   bool ExtendClientIntoTitle() const override { return true; }
 };
diff --git a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc
index b624044..b0c223b 100644
--- a/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/autofill/payments/offer_notification_bubble_views_test_base.h"
 
+#include "build/build_config.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,7 +24,14 @@
       const OfferNotificationBubbleViewsBrowserTest&) = delete;
 };
 
-IN_PROC_BROWSER_TEST_F(OfferNotificationBubbleViewsBrowserTest, Navigation) {
+// Flaky on Linux. crbug.com/1182526
+#if defined(OS_LINUX)
+#define MAYBE_Navigation DISABLED_Navigation
+#else
+#define MAYBE_Navigation Navigation
+#endif
+IN_PROC_BROWSER_TEST_F(OfferNotificationBubbleViewsBrowserTest,
+                       MAYBE_Navigation) {
   static const struct {
     std::string url_navigated_to;
     bool bubble_should_be_visible;
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
index dc31558..e5f61a09 100644
--- a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
@@ -130,8 +130,6 @@
 
   if (name == "devmode_warning") {
     TestBubbleAnchoredToExtensionAction();
-  } else if (name == "ntp_override") {
-    TestControlledNewTabPageBubbleShown(false);
   } else {
     // TODO(tapted): Add cases for all bubble types.
     ADD_FAILURE() << "Unknown dialog: " << name;
@@ -349,82 +347,3 @@
                        InvokeUi_devmode_warning) {
   ShowAndVerifyUi();
 }
-
-class NtpExtensionBubbleViewBrowserTest
-    : public LegacyExtensionMessageBubbleViewBrowserTest {
- public:
-  std::vector<base::Feature> GetFeaturesToDisable() override {
-    std::vector<base::Feature> features_to_disable =
-        LegacyExtensionMessageBubbleViewBrowserTest::GetFeaturesToDisable();
-    features_to_disable.push_back(
-        features::kExtensionSettingsOverriddenDialogs);
-    return features_to_disable;
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    LegacyExtensionMessageBubbleViewBrowserTest::SetUpCommandLine(command_line);
-// The NTP bubble is only enabled by default on Mac, Windows, and CrOS.
-#if !defined(OS_WIN) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
-    extensions::SetNtpPostInstallUiEnabledForTesting(true);
-#endif
-  }
-
-  void TearDownOnMainThread() override {
-#if !defined(OS_WIN) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
-    extensions::SetNtpPostInstallUiEnabledForTesting(false);
-#endif
-    LegacyExtensionMessageBubbleViewBrowserTest::TearDownOnMainThread();
-  }
-};
-
-// Flaky on Ozone https://crbug.com/1178732
-#if defined(USE_OZONE)
-#define MAYBE_TestControlledNewTabPageMessageBubbleLearnMore \
-  DISABLED_TestControlledNewTabPageMessageBubbleLearnMore
-#else
-#define MAYBE_TestControlledNewTabPageMessageBubbleLearnMore \
-  TestControlledNewTabPageMessageBubbleLearnMore
-#endif
-IN_PROC_BROWSER_TEST_F(NtpExtensionBubbleViewBrowserTest,
-                       MAYBE_TestControlledNewTabPageMessageBubbleLearnMore) {
-  TestControlledNewTabPageBubbleShown(true);
-}
-
-// Flaky on Mac, Linux, and ChromeOS https://crbug.com/851655
-#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
-#define MAYBE_TestBubbleClosedAfterExtensionUninstall \
-  DISABLED_TestBubbleClosedAfterExtensionUninstall
-#else
-#define MAYBE_TestBubbleClosedAfterExtensionUninstall \
-  TestBubbleClosedAfterExtensionUninstall
-#endif
-IN_PROC_BROWSER_TEST_F(NtpExtensionBubbleViewBrowserTest,
-                       MAYBE_TestBubbleClosedAfterExtensionUninstall) {
-  TestBubbleClosedAfterExtensionUninstall();
-}
-
-// Flaky on Ozone https://crbug.com/1178717
-#if defined(USE_OZONE)
-#define MAYBE_TestControlledNewTabPageMessageBubble \
-  DISABLED_TestControlledNewTabPageMessageBubble
-#else
-#define MAYBE_TestControlledNewTabPageMessageBubble \
-  TestControlledNewTabPageMessageBubble
-#endif
-IN_PROC_BROWSER_TEST_F(NtpExtensionBubbleViewBrowserTest,
-                       MAYBE_TestControlledNewTabPageMessageBubble) {
-  TestControlledNewTabPageBubbleShown(false);
-}
-
-// BrowserUiTest for the warning bubble that appears when opening a new tab and
-// an extension is controlling it.
-// Flaky on Ozone https://crbug.com/1178733
-#if defined(USE_OZONE)
-#define MAYBE_InvokeUi_ntp_override DISABLED_InvokeUi_ntp_override
-#else
-#define MAYBE_InvokeUi_ntp_override InvokeUi_ntp_override
-#endif
-IN_PROC_BROWSER_TEST_F(NtpExtensionBubbleViewBrowserTest,
-                       MAYBE_InvokeUi_ntp_override) {
-  ShowAndVerifyUi();
-}
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index f97f91aa..8fccef5 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -66,6 +66,11 @@
     g_browser_process->profile_manager()->
         GetProfileAttributesStorage().RemoveObserver(this);
   }
+
+  // WebAppFrameToolbarView::ToolbarButtonContainer is an
+  // ImmersiveModeController::Observer, so it must be destroyed before the
+  // BrowserView destroys the ImmersiveModeController.
+  delete web_app_frame_toolbar_;
 }
 
 void BrowserNonClientFrameView::OnBrowserViewInitViewsComplete() {
@@ -294,68 +299,6 @@
     Layout();
 }
 
-bool BrowserNonClientFrameView::DoesIntersectRect(const views::View* target,
-                                                  const gfx::Rect& rect) const {
-  DCHECK_EQ(target, this);
-  if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect)) {
-    // |rect| is outside the frame's bounds.
-    return false;
-  }
-
-  bool should_leave_to_top_container = false;
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
-  // In immersive mode, the caption buttons container is reparented to the
-  // TopContainerView and hence |rect| should not be claimed here.  See
-  // BrowserNonClientFrameViewChromeOS::OnImmersiveRevealStarted().
-  should_leave_to_top_container =
-      browser_view_->immersive_mode_controller()->IsRevealed();
-#endif
-
-  if (!browser_view_->GetTabStripVisible()) {
-    // Claim |rect| if it is above the top of the topmost client area view.
-    return !should_leave_to_top_container && (rect.y() < GetTopInset(false));
-  }
-
-  // If the rect is outside the bounds of the client area, claim it.
-  gfx::RectF rect_in_client_view_coords_f(rect);
-  View::ConvertRectToTarget(this, frame_->client_view(),
-                            &rect_in_client_view_coords_f);
-  gfx::Rect rect_in_client_view_coords =
-      gfx::ToEnclosingRect(rect_in_client_view_coords_f);
-  if (!frame_->client_view()->HitTestRect(rect_in_client_view_coords))
-    return true;
-
-  // Otherwise, claim |rect| only if it is above the bottom of the tab strip
-  // region view in a non-tab portion.
-  TabStripRegionView* tab_strip_region_view =
-      browser_view_->tab_strip_region_view();
-
-  // The |tab_strip_region_view| may not be in a Widget (e.g. when switching
-  // into immersive reveal the BrowserView's TopContainerView is reparented).
-  if (tab_strip_region_view->GetWidget()) {
-    gfx::RectF rect_in_region_view_coords_f(rect);
-    View::ConvertRectToTarget(this, tab_strip_region_view,
-                              &rect_in_region_view_coords_f);
-    gfx::Rect rect_in_region_view_coords =
-        gfx::ToEnclosingRect(rect_in_region_view_coords_f);
-    if (rect_in_region_view_coords.y() >=
-        tab_strip_region_view->GetLocalBounds().bottom()) {
-      // |rect| is below the tab_strip_region_view.
-      return false;
-    }
-
-    if (tab_strip_region_view->HitTestRect(rect_in_region_view_coords)) {
-      // Claim |rect| if it is in a non-tab portion of the tabstrip.
-      return tab_strip_region_view->IsRectInWindowCaption(
-          rect_in_region_view_coords);
-    }
-  }
-
-  // We claim |rect| because it is above the bottom of the tabstrip, but
-  // not in the tabstrip itself.
-  return !should_leave_to_top_container;
-}
-
 void BrowserNonClientFrameView::OnProfileAdded(
     const base::FilePath& profile_path) {
   OnProfileAvatarChanged(profile_path);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 8760b6b..875ba7da 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -157,8 +157,6 @@
 
   // views::NonClientFrameView:
   void ChildPreferredSizeChanged(views::View* child) override;
-  bool DoesIntersectRect(const views::View* target,
-                         const gfx::Rect& rect) const override;
 
   // ProfileAttributesStorage::Observer:
   void OnProfileAdded(const base::FilePath& profile_path) override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index 945848b..05b1a991 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -401,6 +401,27 @@
   }
 }
 
+bool BrowserNonClientFrameViewChromeOS::DoesIntersectRect(
+    const views::View* target,
+    const gfx::Rect& rect) const {
+  DCHECK_EQ(target, this);
+  if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect)) {
+    // |rect| is outside the frame's bounds.
+    return false;
+  }
+
+  bool should_leave_to_top_container = false;
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  // In immersive mode, the caption buttons container is reparented to the
+  // TopContainerView and hence |rect| should not be claimed here.  See
+  // BrowserNonClientFrameViewChromeOS::OnImmersiveRevealStarted().
+  should_leave_to_top_container =
+      browser_view()->immersive_mode_controller()->IsRevealed();
+#endif
+
+  return !should_leave_to_top_container;
+}
+
 SkColor BrowserNonClientFrameViewChromeOS::GetTitleColor() {
   return browser_view()->GetRegularOrGuestSession()
              ? kNormalWindowTitleTextColor
@@ -561,7 +582,13 @@
 }
 
 void BrowserNonClientFrameViewChromeOS::OnImmersiveRevealEnded() {
-  AddChildViewAt(caption_button_container_, 0);
+  // Ensure the caption button container receives events before the browser view
+  // by placing it higher in the z-order.
+  // [0] - FrameAnimatorView
+  // [1] - BrowserView
+  // [2] - FrameCaptionButtonContainerView
+  const int kCaptionButtonContainerIndex = 2;
+  AddChildViewAt(caption_button_container_, kCaptionButtonContainerIndex);
   if (web_app_frame_toolbar())
     AddChildViewAt(web_app_frame_toolbar(), 0);
   Layout();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
index 97df69a7..4bbc1a59 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.h
@@ -79,6 +79,8 @@
   gfx::Size GetMinimumSize() const override;
   void OnThemeChanged() override;
   void ChildPreferredSizeChanged(views::View* child) override;
+  bool DoesIntersectRect(const views::View* target,
+                         const gfx::Rect& rect) const override;
 
   // BrowserFrameHeaderChromeOS::AppearanceProvider:
   SkColor GetTitleColor() override;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index 387e4c4..1eeda0de 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -338,6 +338,8 @@
 }
 
 void BrowserNonClientFrameViewMac::Layout() {
+  NonClientFrameView::Layout();
+
   const int available_height = GetTopInset(true);
   int leading_x = kFramePaddingLeft;
   int trailing_x = width();
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
index 58cb717..f623223 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
@@ -61,12 +61,15 @@
 #define MAYBE_HitTestPopupTopChrome HitTestPopupTopChrome
 #endif
 TEST_F(BrowserNonClientFrameViewPopupTest, MAYBE_HitTestPopupTopChrome) {
-  EXPECT_FALSE(frame_view_->HitTestRect(gfx::Rect(-1, 4, 1, 1)));
-  EXPECT_FALSE(frame_view_->HitTestRect(gfx::Rect(4, -1, 1, 1)));
+  constexpr gfx::Rect kLeftOfFrame(-1, 4, 1, 1);
+  EXPECT_FALSE(frame_view_->HitTestRect(kLeftOfFrame));
+
+  constexpr gfx::Rect kAboveFrame(4, -1, 1, 1);
+  EXPECT_FALSE(frame_view_->HitTestRect(kAboveFrame));
+
   const int top_inset = frame_view_->GetTopInset(false);
-  EXPECT_FALSE(frame_view_->HitTestRect(gfx::Rect(4, top_inset, 1, 1)));
-  if (top_inset > 0)
-    EXPECT_TRUE(frame_view_->HitTestRect(gfx::Rect(4, top_inset - 1, 1, 1)));
+  const gfx::Rect in_browser_view(4, top_inset, 1, 1);
+  EXPECT_TRUE(frame_view_->HitTestRect(in_browser_view));
 }
 
 class BrowserNonClientFrameViewTabbedTest
@@ -108,7 +111,9 @@
 
   // Hits client portions of the tabstrip (near the bottom left corner of the
   // first tab).
-  EXPECT_FALSE(frame_view_->HitTestRect(gfx::Rect(
+  EXPECT_TRUE(frame_view_->HitTestRect(gfx::Rect(
+      tabstrip_bounds.x() + 10, tabstrip_bounds.bottom() - 10, 1, 1)));
+  EXPECT_TRUE(frame_view_->browser_view()->HitTestRect(gfx::Rect(
       tabstrip_bounds.x() + 10, tabstrip_bounds.bottom() - 10, 1, 1)));
 
 // Tabs extend to the top of the tabstrip everywhere in this test context on
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index a06bb168..d2e2c245 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -2899,6 +2899,12 @@
 }
 
 void BrowserView::AddedToWidget() {
+  // BrowserView may be added to a widget more than once if the user changes
+  // themes after starting the browser. Do not re-initialize BrowserView in
+  // this case.
+  if (initialized_)
+    return;
+
   views::ClientView::AddedToWidget();
 
   widget_observation_.Observe(GetWidget());
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index 3ae9bc23..4520703 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -403,6 +403,7 @@
   LayoutCaptionButtons();
   LayoutTitleBar();
   LayoutClientView();
+  NonClientFrameView::Layout();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
index c788b1c..8a80fa1c 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.cc
@@ -18,6 +18,7 @@
 #include "ui/gfx/font.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/view_utils.h"
 #include "ui/views/window/caption_button_layout_constants.h"
 #include "ui/views/window/frame_caption_button.h"
 
@@ -594,6 +595,11 @@
 
   client_view_bounds_ = CalculateClientAreaBounds(
       host->width(), host->height());
+
+  // When a theme change occurs, Layout() may be called before
+  // client_view_ is set.
+  if (client_view_)
+    client_view_->SetBoundsRect(client_view_bounds_);
 }
 
 gfx::Size OpaqueBrowserFrameViewLayout::GetPreferredSize(
@@ -606,10 +612,20 @@
 
 void OpaqueBrowserFrameViewLayout::ViewAdded(views::View* host,
                                              views::View* view) {
+  if (views::IsViewClass<views::ClientView>(view)) {
+    client_view_ = static_cast<views::ClientView*>(view);
+    return;
+  }
+
   SetView(view->GetID(), view);
 }
 
 void OpaqueBrowserFrameViewLayout::ViewRemoved(views::View* host,
                                                views::View* view) {
+  if (views::IsViewClass<views::ClientView>(view)) {
+    client_view_ = nullptr;
+    return;
+  }
+
   SetView(view->GetID(), nullptr);
 }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
index 3a8d890..ec7d845f 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -217,6 +217,8 @@
   std::vector<views::FrameButton> leading_buttons_;
   std::vector<views::FrameButton> trailing_buttons_;
 
+  views::ClientView* client_view_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(OpaqueBrowserFrameViewLayout);
 };
 
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
index 6a74e43..6ccc283 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.cc
@@ -29,6 +29,7 @@
   DCHECK(browser_view_);
   DCHECK(web_app::AppBrowserController::IsWebApp(browser_view_->browser()));
   SetID(VIEW_ID_WEB_APP_FRAME_TOOLBAR);
+  SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
 
   {
     // TODO(tluk) fix the need for both LayoutInContainer() and a layout
@@ -225,6 +226,24 @@
   return left_container_ ? left_container_->reload_button() : nullptr;
 }
 
+bool WebAppFrameToolbarView::DoesIntersectRect(const View* target,
+                                               const gfx::Rect& rect) const {
+  DCHECK_EQ(target, this);
+  if (!views::ViewTargeterDelegate::DoesIntersectRect(this, rect))
+    return false;
+
+  // If the rect is inside the bounds of the center_container, do not claim it.
+  // There is no actionable content in the center_container, and it overlaps
+  // tabs in tabbed PWA windows.
+  gfx::RectF rect_in_center_container_coords_f(rect);
+  View::ConvertRectToTarget(this, center_container_,
+                            &rect_in_center_container_coords_f);
+  gfx::Rect rect_in_client_view_coords =
+      gfx::ToEnclosingRect(rect_in_center_container_coords_f);
+
+  return !center_container_->HitTestRect(rect_in_client_view_coords);
+}
+
 PageActionIconController*
 WebAppFrameToolbarView::GetPageActionIconControllerForTesting() {
   return right_container_->page_action_icon_controller();
diff --git a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
index ad74333..26280bb 100644
--- a/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
+++ b/chrome/browser/ui/views/web_apps/frame_toolbar/web_app_frame_toolbar_view.h
@@ -15,9 +15,11 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/views/accessible_pane_view.h"
 #include "ui/views/metadata/metadata_header_macros.h"
+#include "ui/views/view_targeter_delegate.h"
 
 namespace views {
 class View;
+class ViewTargeterDelegate;
 class Widget;
 }  // namespace views
 
@@ -29,7 +31,8 @@
 
 // A container for web app buttons in the title bar.
 class WebAppFrameToolbarView : public views::AccessiblePaneView,
-                               public ToolbarButtonProvider {
+                               public ToolbarButtonProvider,
+                               public views::ViewTargeterDelegate {
  public:
   METADATA_HEADER(WebAppFrameToolbarView);
   WebAppFrameToolbarView(views::Widget* widget, BrowserView* browser_view);
@@ -72,6 +75,10 @@
   ToolbarButton* GetBackButton() override;
   ReloadButton* GetReloadButton() override;
 
+  // views::ViewTargeterDelegate
+  bool DoesIntersectRect(const View* target,
+                         const gfx::Rect& rect) const override;
+
   WebAppNavigationButtonContainer* get_left_container_for_testing() {
     return left_container_;
   }
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index 7a967613..2dd5571 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -223,6 +223,8 @@
 #include "chromeos/components/media_app_ui/url_constants.h"
 #include "chromeos/components/multidevice/debug_webui/proximity_auth_ui.h"
 #include "chromeos/components/multidevice/debug_webui/url_constants.h"
+#include "chromeos/components/personalization_app/personalization_app_ui.h"
+#include "chromeos/components/personalization_app/personalization_app_url_constants.h"
 #include "chromeos/components/print_management/print_management_ui.h"
 #include "chromeos/components/print_management/url_constants.h"
 #include "chromeos/components/scanning/scanning_ui.h"
@@ -741,8 +743,7 @@
   }
   if (url.host_piece() == chrome::kChromeUICrostiniInstallerHost)
     return &NewWebUI<chromeos::CrostiniInstallerUI>;
-  if (chromeos::CrostiniUpgraderUI::IsEnabled() &&
-      url.host_piece() == chrome::kChromeUICrostiniUpgraderHost)
+  if (url.host_piece() == chrome::kChromeUICrostiniUpgraderHost)
     return &NewWebUI<chromeos::CrostiniUpgraderUI>;
   if (url.host_piece() == chrome::kChromeUICryptohomeHost)
     return &NewWebUI<chromeos::CryptohomeUI>;
@@ -839,6 +840,10 @@
   if (url.host_piece() == chrome::kChromeUIPluginVmInternalHost) {
     return &NewWebUI<chromeos::PluginVmInternalUI>;
   }
+  if (url.host_piece() == chromeos::kChromeUIPersonalizationAppHost &&
+      chromeos::features::IsWallpaperWebUIEnabled()) {
+    return &NewWebUI<chromeos::PersonalizationAppUI>;
+  }
 
 #if !defined(OFFICIAL_BUILD)
 #if !defined(USE_REAL_DBUS_CLIENTS)
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
index ff16751..b1dcb41 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.cc
@@ -34,11 +34,6 @@
 
 namespace chromeos {
 
-bool CrostiniUpgraderUI::IsEnabled() {
-  return base::FeatureList::IsEnabled(
-      chromeos::features::kCrostiniWebUIUpgrader);
-}
-
 void AddStringResources(content::WebUIDataSource* source) {
   static constexpr webui::LocalizedString kStrings[] = {
       {"upgrade", IDS_CROSTINI_UPGRADER_UPGRADE_BUTTON},
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
index 13c5605..db89c45 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/crostini_upgrader_ui.h
@@ -22,8 +22,6 @@
     : public ui::MojoWebDialogUI,
       public chromeos::crostini_upgrader::mojom::PageHandlerFactory {
  public:
-  static bool IsEnabled();
-
   explicit CrostiniUpgraderUI(content::WebUI* web_ui);
   ~CrostiniUpgraderUI() override;
 
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
index 9754465..5c489b5 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
@@ -18,7 +18,7 @@
 #include "base/strings/string_util.h"
 #include "base/system/sys_info.h"
 #include "base/values.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/profiles/profile.h"
@@ -102,7 +102,7 @@
 
 }  // namespace
 
-KioskAppsHandler::KioskAppsHandler(OwnerSettingsServiceChromeOS* service)
+KioskAppsHandler::KioskAppsHandler(OwnerSettingsServiceAsh* service)
     : kiosk_app_manager_(KioskAppManager::Get()),
       initialized_(false),
       is_kiosk_enabled_(false),
diff --git a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
index a37075ad..3cced8e 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h
@@ -12,9 +12,9 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/ash/app_mode/kiosk_app_manager_observer.h"
-// TODO(https://crbug.com/1164001): move OwnerSettingsServiceChromeOS to forward
+// TODO(https://crbug.com/1164001): move OwnerSettingsServiceAsh to forward
 // declaration when moved to chrome/browser/ash/.
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 namespace base {
@@ -26,7 +26,7 @@
 class KioskAppsHandler : public content::WebUIMessageHandler,
                          public KioskAppManagerObserver {
  public:
-  explicit KioskAppsHandler(OwnerSettingsServiceChromeOS* service);
+  explicit KioskAppsHandler(OwnerSettingsServiceAsh* service);
   ~KioskAppsHandler() override;
 
   // content::WebUIMessageHandler overrides:
@@ -67,7 +67,7 @@
   bool initialized_;
   bool is_kiosk_enabled_;
   bool is_auto_launch_enabled_;
-  OwnerSettingsServiceChromeOS* const owner_settings_service_;  // not owned
+  OwnerSettingsServiceAsh* const owner_settings_service_;  // not owned
   base::WeakPtrFactory<KioskAppsHandler> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(KioskAppsHandler);
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index bc38076..6caf61fd 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -48,7 +48,7 @@
 #include "ui/base/webui/web_ui_util.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h"
 #endif
 
@@ -367,7 +367,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   auto kiosk_app_handler = std::make_unique<chromeos::KioskAppsHandler>(
-      ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile));
+      ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile));
   web_ui->AddMessageHandler(std::move(kiosk_app_handler));
 #endif
 
diff --git a/chrome/browser/ui/webui/flags/flags_ui.cc b/chrome/browser/ui/webui/flags/flags_ui.cc
index aba5d32c..612a3e7 100644
--- a/chrome/browser/ui/webui/flags/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags/flags_ui.cc
@@ -43,8 +43,8 @@
 #include "base/command_line.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/ash/login/session/user_session_manager.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/ash/settings/owner_flags_storage.h"
@@ -114,8 +114,8 @@
   // Note that |dom_handler| is owned by the web ui that owns |flags_ui|, so
   // it is still alive if |flags_ui| is.
   if (current_user_is_owner) {
-    ash::OwnerSettingsServiceChromeOS* service =
-        ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(profile);
+    ash::OwnerSettingsServiceAsh* service =
+        ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(profile);
     dom_handler->Init(new chromeos::about_flags::OwnerFlagsStorage(
                           profile->GetPrefs(), service),
                       flags_ui::kOwnerAccessToFlags);
@@ -232,10 +232,10 @@
   // Bypass possible incognito profile.
   Profile* original_profile = profile->GetOriginalProfile();
   if (base::SysInfo::IsRunningOnChromeOS() &&
-      ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+      ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(
           original_profile)) {
-    ash::OwnerSettingsServiceChromeOS* service =
-        ash::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
+    ash::OwnerSettingsServiceAsh* service =
+        ash::OwnerSettingsServiceAshFactory::GetForBrowserContext(
             original_profile);
     service->IsOwnerAsync(base::BindOnce(&FinishInitialization<T>,
                                          weak_factory.GetWeakPtr(),
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index 6dea94a..2655cf5c7 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -12,8 +12,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/ash/login/startup_utils.h"
 #include "chrome/browser/ash/login/wizard_controller.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
@@ -32,8 +32,8 @@
 
 using chromeos::CrosSettings;
 using chromeos::DBusThreadManager;
-using chromeos::OwnerSettingsServiceChromeOS;
-using chromeos::OwnerSettingsServiceChromeOSFactory;
+using chromeos::OwnerSettingsServiceAsh;
+using chromeos::OwnerSettingsServiceAshFactory;
 using chromeos::UpdateEngineClient;
 using chromeos::WizardController;
 
@@ -182,10 +182,10 @@
 
 void VersionUpdaterCros::SetChannel(const std::string& channel,
                                     bool is_powerwash_allowed) {
-  OwnerSettingsServiceChromeOS* service =
+  OwnerSettingsServiceAsh* service =
       context_
-          ? OwnerSettingsServiceChromeOSFactory::GetInstance()
-                ->GetForBrowserContext(context_)
+          ? OwnerSettingsServiceAshFactory::GetInstance()->GetForBrowserContext(
+                context_)
           : nullptr;
   // For local owner set the field in the policy blob.
   if (service)
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index 092beff6..8295a8b 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -52,8 +52,8 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/constants/ash_switches.h"
 #include "base/i18n/time_formatting.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
 #include "chrome/browser/ash/settings/cros_settings.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
@@ -135,9 +135,9 @@
   }
 
   // On non-managed machines, only the local owner can change the channel.
-  ash::OwnerSettingsServiceChromeOS* service =
-      ash::OwnerSettingsServiceChromeOSFactory::GetInstance()
-          ->GetForBrowserContext(profile);
+  ash::OwnerSettingsServiceAsh* service =
+      ash::OwnerSettingsServiceAshFactory::GetInstance()->GetForBrowserContext(
+          profile);
   return service && service->IsOwner();
 }
 
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 579e0ac..c932e7ed 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -102,8 +102,8 @@
 #include "chrome/browser/ash/account_manager/account_manager_util.h"
 #include "chrome/browser/ash/assistant/assistant_util.h"
 #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos.h"
-#include "chrome/browser/ash/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
+#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
 #include "chrome/browser/chromeos/kerberos/kerberos_credentials_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 65862352..55a8e0b 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -112,6 +112,7 @@
       "//chromeos/components/eche_app_ui",
       "//chromeos/components/help_app_ui",
       "//chromeos/components/media_app_ui",
+      "//chromeos/components/personalization_app",
       "//chromeos/strings",
       "//components/arc:arc_base",
       "//components/arc/mojom",
@@ -314,6 +315,7 @@
 
   if (is_chromeos_ash) {
     deps += [
+      "//ash:test_support",
       "//chrome/browser/chromeos",
       "//chrome/browser/ui",
     ]
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index 4f010523..c4fb300 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -228,6 +228,7 @@
       "web_app_handler_registration_utils_win_unittest.cc",
       "web_app_protocol_handler_registration_win_unittest.cc",
       "web_app_run_on_os_login_win_unittest.cc",
+      "web_app_shortcut_win_unittest.cc",
     ]
   }
 
diff --git a/chrome/browser/web_applications/components/system_web_app_types.h b/chrome/browser/web_applications/components/system_web_app_types.h
index 25ee6a6f..37974b5 100644
--- a/chrome/browser/web_applications/components/system_web_app_types.h
+++ b/chrome/browser/web_applications/components/system_web_app_types.h
@@ -30,6 +30,7 @@
   CONNECTIVITY_DIAGNOSTICS = 12,
   ECHE = 13,
   CROSH = 14,
+  PERSONALIZATION = 15,
 
   // When adding a new System App, remember to:
   //
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.cc b/chrome/browser/web_applications/components/web_app_shortcut.cc
index 6023d0ec..7b8ae03 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut.cc
@@ -96,12 +96,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-ShortcutLocations::ShortcutLocations()
-    : on_desktop(false),
-      applications_menu_location(APP_MENU_LOCATION_NONE),
-      in_quick_launch_bar(false),
-      in_startup(false) {}
-
 std::string GenerateApplicationNameFromInfo(const ShortcutInfo& shortcut_info) {
   // TODO(loyso): Remove this empty()/non-empty difference.
   if (shortcut_info.extension_id.empty())
diff --git a/chrome/browser/web_applications/components/web_app_shortcut.h b/chrome/browser/web_applications/components/web_app_shortcut.h
index 08b31bab..acd4692 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut.h
+++ b/chrome/browser/web_applications/components/web_app_shortcut.h
@@ -80,22 +80,20 @@
 
 // Info about which locations to create app shortcuts in.
 struct ShortcutLocations {
-  ShortcutLocations();
+  bool on_desktop = false;
 
-  bool on_desktop;
-
-  ApplicationsMenuLocation applications_menu_location;
+  ApplicationsMenuLocation applications_menu_location = APP_MENU_LOCATION_NONE;
 
   // For Windows, this refers to quick launch bar prior to Win7. In Win7,
   // this means "pin to taskbar". For Mac/Linux, this could be used for
   // Mac dock or the gnome/kde application launcher. However, those are not
   // implemented yet.
-  bool in_quick_launch_bar;
+  bool in_quick_launch_bar = false;
 
   // For Windows, this refers to the Startup folder.
   // For Mac, this refers to the Login Items list.
   // For Linux, this refers to the autostart folder.
-  bool in_startup;
+  bool in_startup = false;
 };
 
 // This encodes the cause of shortcut creation as the correct behavior in each
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index 707282e..70956261 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -532,8 +532,8 @@
       {creation_locations.applications_menu_location ==
            APP_MENU_LOCATION_SUBDIR_CHROMEAPPS,
        ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR},
-      {// For Win7+, |in_quick_launch_bar| indicates that we are pinning to
-       // taskbar. This needs to be handled by callers.
+      {// For Windows 7 and 8, |in_quick_launch_bar| indicates that we are
+       // pinning to taskbar. This needs to be handled by callers.
        creation_locations.in_quick_launch_bar &&
            base::win::CanPinShortcutToTaskbar(),
        ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH},
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win_unittest.cc b/chrome/browser/web_applications/components/web_app_shortcut_win_unittest.cc
new file mode 100644
index 0000000..670201244
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win_unittest.cc
@@ -0,0 +1,174 @@
+// 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/web_applications/components/web_app_shortcut_win.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/shortcut.h"
+#include "base/win/windows_version.h"
+#include "chrome/browser/web_applications/components/web_app_shortcut.h"
+#include "chrome/browser/web_applications/test/web_app_test.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/installer/util/shell_util.h"
+#include "chrome/installer/util/util_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_family.h"
+
+namespace web_app {
+namespace internals {
+namespace {
+
+bool CreateTestAppShortcut(const base::FilePath& shortcut_path,
+                           const base::FilePath::StringType& profile_name) {
+  base::CommandLine args_cl(base::CommandLine::NO_PROGRAM);
+  args_cl.AppendSwitchNative(switches::kProfileDirectory, profile_name);
+  args_cl.AppendSwitchASCII(switches::kAppId, "123");
+
+  base::win::ShortcutProperties shortcut_properties;
+  shortcut_properties.set_arguments(args_cl.GetArgumentsString());
+  shortcut_properties.set_target(base::FilePath(FILE_PATH_LITERAL("target")));
+  return base::win::CreateOrUpdateShortcutLink(
+      shortcut_path, shortcut_properties, base::win::SHORTCUT_CREATE_ALWAYS);
+}
+
+base::FilePath GetShortcutPath(const base::FilePath shortcut_dir,
+                               const base::FilePath::StringType shortcut_name) {
+  return shortcut_dir.Append(shortcut_name).AddExtension(installer::kLnkExt);
+}
+
+}  // namespace
+
+using WebAppShortcutWinTest = WebAppTest;
+
+TEST_F(WebAppShortcutWinTest, GetSanitizedFileName) {
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("")), GetSanitizedFileName(u""));
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("clean filename")),
+            GetSanitizedFileName(u"clean filename"));
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("illegal_chars.._")),
+            GetSanitizedFileName(u"illegal*chars..."));
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("path_separator")),
+            GetSanitizedFileName(u"path/separator"));
+  EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("___")),
+            GetSanitizedFileName(u"***"));
+}
+
+TEST_F(WebAppShortcutWinTest, GetShortcutPaths) {
+  ShortcutLocations shortcut_locations;
+  EXPECT_TRUE(GetShortcutPaths(shortcut_locations).empty());
+
+  // The location APP_MENU_LOCATION_HIDDEN is not used on Windows.
+  shortcut_locations.applications_menu_location = APP_MENU_LOCATION_HIDDEN;
+  EXPECT_TRUE(GetShortcutPaths(shortcut_locations).empty());
+
+  shortcut_locations.on_desktop = true;
+  shortcut_locations.applications_menu_location =
+      APP_MENU_LOCATION_SUBDIR_CHROMEAPPS;
+  shortcut_locations.in_quick_launch_bar = true;
+  shortcut_locations.in_startup = true;
+  const std::vector<base::FilePath> result =
+      GetShortcutPaths(shortcut_locations);
+  std::vector<ShellUtil::ShortcutLocation> expected_locations{
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
+      ShellUtil::SHORTCUT_LOCATION_STARTUP};
+  if (base::win::GetVersion() < base::win::Version::WIN10)
+    expected_locations.push_back(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH);
+
+  base::FilePath expected_result;
+  for (const auto& location : expected_locations) {
+    ASSERT_TRUE(ShellUtil::GetShortcutPath(location, ShellUtil::CURRENT_USER,
+                                           &expected_result));
+    EXPECT_NE(result.end(),
+              std::find(result.begin(), result.end(), expected_result));
+  }
+}
+
+TEST_F(WebAppShortcutWinTest, CheckAndSaveIcon) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const base::FilePath icon_file =
+      temp_dir.GetPath().Append(FILE_PATH_LITERAL("test.ico"));
+
+  gfx::ImageFamily image_family;
+  image_family.Add(gfx::Image(CreateDefaultApplicationIcon(5)));
+  EXPECT_TRUE(CheckAndSaveIcon(icon_file, image_family,
+                               /*refresh_shell_icon_cache=*/false));
+  // CheckAndSaveIcon() should succeed even if called multiple times.
+  EXPECT_TRUE(CheckAndSaveIcon(icon_file, image_family,
+                               /*refresh_shell_icon_cache=*/false));
+  image_family.clear();
+  image_family.Add(gfx::Image(CreateDefaultApplicationIcon(6)));
+  EXPECT_TRUE(CheckAndSaveIcon(icon_file, image_family,
+                               /*refresh_shell_icon_cache=*/false));
+}
+
+TEST_F(WebAppShortcutWinTest, FindAppShortcutsByProfileAndTitle) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  const base::FilePath shortcut_dir = temp_dir.GetPath();
+
+  const base::FilePath::StringType shortcut_name =
+      FILE_PATH_LITERAL("test shortcut");
+  const base::FilePath shortcut_path =
+      GetShortcutPath(shortcut_dir, shortcut_name);
+  const base::FilePath duplicate_shortcut_path =
+      GetShortcutPath(shortcut_dir, FILE_PATH_LITERAL("test shortcut (5)"));
+  const base::FilePath other_shortcut_path =
+      GetShortcutPath(shortcut_dir, FILE_PATH_LITERAL("another test shortcut"));
+  const base::FilePath other_profile_shortcut_path = GetShortcutPath(
+      shortcut_dir, FILE_PATH_LITERAL("shortcut for another profile"));
+
+  const base::FilePath profile_path(FILE_PATH_LITERAL("test/profile/path"));
+  const base::FilePath::StringType profile_name =
+      profile_path.BaseName().value();
+
+  ASSERT_TRUE(CreateTestAppShortcut(shortcut_path, profile_name));
+  ASSERT_TRUE(CreateTestAppShortcut(duplicate_shortcut_path, profile_name));
+  ASSERT_TRUE(CreateTestAppShortcut(other_shortcut_path, profile_name));
+  ASSERT_TRUE(CreateTestAppShortcut(other_profile_shortcut_path,
+                                    FILE_PATH_LITERAL("other profile")));
+
+  // Find |shortcut_name| by name. The specified shortcut and its duplicate
+  // should be found.
+  std::vector<base::FilePath> result = FindAppShortcutsByProfileAndTitle(
+      shortcut_dir, profile_path, base::WideToUTF16(shortcut_name));
+  EXPECT_EQ(2u, result.size());
+  EXPECT_NE(result.end(),
+            std::find(result.begin(), result.end(), shortcut_path));
+  EXPECT_NE(result.end(),
+            std::find(result.begin(), result.end(), duplicate_shortcut_path));
+  EXPECT_EQ(result.end(),
+            std::find(result.begin(), result.end(), other_shortcut_path));
+  EXPECT_EQ(result.end(), std::find(result.begin(), result.end(),
+                                    other_profile_shortcut_path));
+
+  // Find all shortcuts for |profile_name|. The shortcuts matching that profile
+  // should be found.
+  result = FindAppShortcutsByProfileAndTitle(shortcut_dir, profile_path, u"");
+  EXPECT_EQ(3u, result.size());
+  EXPECT_NE(result.end(),
+            std::find(result.begin(), result.end(), shortcut_path));
+  EXPECT_NE(result.end(),
+            std::find(result.begin(), result.end(), duplicate_shortcut_path));
+  EXPECT_NE(result.end(),
+            std::find(result.begin(), result.end(), other_shortcut_path));
+  EXPECT_EQ(result.end(), std::find(result.begin(), result.end(),
+                                    other_profile_shortcut_path));
+}
+
+TEST_F(WebAppShortcutWinTest, GetIconFilePath) {
+  const base::FilePath web_app_path(FILE_PATH_LITERAL("test\\web\\app\\dir"));
+  EXPECT_EQ(GetIconFilePath(web_app_path, u"test app name"),
+            base::FilePath(
+                FILE_PATH_LITERAL("test\\web\\app\\dir\\test app name.ico")));
+  EXPECT_EQ(GetIconFilePath(web_app_path, u"***"),
+            base::FilePath(FILE_PATH_LITERAL("test\\web\\app\\dir\\___.ico")));
+}
+
+}  // namespace internals
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/external_web_app_manager_browsertest.cc b/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
index 80796032..274d719 100644
--- a/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
@@ -28,6 +28,15 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "ash/public/cpp/test/app_list_test_api.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
+#endif
+
 namespace web_app {
 
 class ExternalWebAppManagerBrowserTest
@@ -87,7 +96,13 @@
     ExternalWebAppManager::SetFileUtilsForTesting(&file_utils);
 
     std::vector<base::Value> app_configs;
-    app_configs.push_back(*base::JSONReader::Read(app_config_string));
+    base::JSONReader::ValueWithError json_parse_result =
+        base::JSONReader::ReadAndReturnValueWithError(app_config_string);
+    EXPECT_TRUE(json_parse_result.value)
+        << "JSON parse error: " << json_parse_result.error_message;
+    if (!json_parse_result.value)
+      return base::nullopt;
+    app_configs.push_back(*std::move(json_parse_result.value));
     ExternalWebAppManager::SetConfigsForTesting(&app_configs);
 
     base::Optional<InstallResultCode> code;
@@ -592,6 +607,73 @@
   EXPECT_TRUE(registrar().WasInstalledByOem(app_id));
 }
 
+IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
+                       UninstallFromTwoItemAppListFolder) {
+  GURL default_app_start_url("https://example.org/");
+  GURL user_app_start_url("https://test.org/");
+
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile());
+  AppListClientImpl::GetInstance()->UpdateProfile();
+  ash::AppListTestApi app_list_test_api;
+  app_list::AppListSyncableService* app_list_syncable_service =
+      app_list::AppListSyncableServiceFactory::GetForProfile(profile());
+
+  // Install default app.
+  constexpr char kAppConfigTemplate[] =
+      R"({
+        "app_url": "$1",
+        "launch_container": "window",
+        "user_type": ["unmanaged"],
+        "only_use_offline_manifest": true,
+        "offline_manifest": {
+          "name": "Test default app",
+          "display": "standalone",
+          "start_url": "$1",
+          "scope": "$1",
+          "icon_any_pngs": ["icon.png"]
+        }
+      })";
+  std::string app_config = base::ReplaceStringPlaceholders(
+      kAppConfigTemplate, {default_app_start_url.spec()}, nullptr);
+  EXPECT_EQ(SyncDefaultAppConfig(default_app_start_url, app_config),
+            InstallResultCode::kSuccessOfflineOnlyInstall);
+  AppId default_app_id = GenerateAppIdFromURL(default_app_start_url);
+
+  // Install user app.
+  auto web_application_info = std::make_unique<WebApplicationInfo>();
+  web_application_info->start_url = user_app_start_url;
+  web_application_info->title = base::UTF8ToUTF16("Test user app");
+  AppId user_app_id = InstallWebApp(profile(), std::move(web_application_info));
+
+  // Ensure the UI receives these apps.
+  proxy->FlushMojoCallsForTesting();
+
+  // Put apps in app list folder.
+  std::string folder_id =
+      app_list_test_api.CreateFolderWithApps({default_app_id, user_app_id});
+  EXPECT_EQ(app_list_syncable_service->GetSyncItem(default_app_id)->parent_id,
+            folder_id);
+  EXPECT_EQ(app_list_syncable_service->GetSyncItem(user_app_id)->parent_id,
+            folder_id);
+
+  // Uninstall default app.
+  proxy->UninstallSilently(default_app_id, apps::mojom::UninstallSource::kUser);
+
+  // Ensure the UI receives the app uninstall.
+  apps::AppServiceProxyFactory::GetForProfile(profile())
+      ->FlushMojoCallsForTesting();
+
+  // Default app should be removed from local app list but remain in sync list.
+  EXPECT_FALSE(registrar().IsInstalled(default_app_id));
+  EXPECT_TRUE(registrar().IsInstalled(user_app_id));
+  EXPECT_FALSE(app_list_test_api.HasApp(default_app_id));
+  EXPECT_TRUE(app_list_test_api.HasApp(user_app_id));
+  EXPECT_EQ(app_list_syncable_service->GetSyncItem(default_app_id)->parent_id,
+            "");
+  EXPECT_EQ(app_list_syncable_service->GetSyncItem(user_app_id)->parent_id, "");
+}
+
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/proto/web_app.proto b/chrome/browser/web_applications/proto/web_app.proto
index 698996a..3df7e89 100644
--- a/chrome/browser/web_applications/proto/web_app.proto
+++ b/chrome/browser/web_applications/proto/web_app.proto
@@ -73,6 +73,7 @@
     CONNECTIVITY_DIAGNOSTICS = 12;
     ECHE = 13;
     CROSH = 14;
+    PERSONALIZATION = 15;
   };
 
   optional SystemAppType system_app_type = 1;
diff --git a/chrome/browser/web_applications/system_web_app_manager.cc b/chrome/browser/web_applications/system_web_app_manager.cc
index a8a4db7..3103d67 100644
--- a/chrome/browser/web_applications/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/system_web_app_manager.cc
@@ -64,6 +64,7 @@
 #include "chrome/browser/ash/web_applications/help_app_web_app_info.h"
 #include "chrome/browser/ash/web_applications/media_web_app_info.h"
 #include "chrome/browser/ash/web_applications/os_settings_web_app_info.h"
+#include "chrome/browser/ash/web_applications/personalization_app_info.h"
 #include "chrome/browser/ash/web_applications/print_management_web_app_info.h"
 #include "chrome/browser/ash/web_applications/scanning_system_web_app_info.h"
 #include "chrome/browser/ash/web_applications/terminal_system_web_app_info.h"
@@ -72,6 +73,7 @@
 #include "chromeos/components/connectivity_diagnostics/url_constants.h"
 #include "chromeos/components/help_app_ui/url_constants.h"
 #include "chromeos/components/media_app_ui/url_constants.h"
+#include "chromeos/components/personalization_app/personalization_app_url_constants.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #include "extensions/common/constants.h"
 #if !defined(OFFICIAL_BUILD)
@@ -247,6 +249,16 @@
         false;
   }
 
+  if (SystemWebAppManager::IsAppEnabled(SystemAppType::PERSONALIZATION)) {
+    infos.emplace(
+        SystemAppType::PERSONALIZATION,
+        SystemAppInfo(
+            "Personalization", GURL(chromeos::kChromeUIPersonalizationAppURL),
+            base::BindRepeating(&CreateWebAppInfoForPersonalizationApp)));
+    auto& personalization_info = infos.at(SystemAppType::PERSONALIZATION);
+    personalization_info.capture_navigations = true;
+  }
+
 #if !defined(OFFICIAL_BUILD)
   if (SystemWebAppManager::IsAppEnabled(SystemAppType::TELEMETRY)) {
     infos.emplace(
@@ -388,6 +400,8 @@
       return false;
     case SystemAppType::ECHE:
       return base::FeatureList::IsEnabled(chromeos::features::kEcheSWA);
+    case SystemAppType::PERSONALIZATION:
+      return chromeos::features::IsWallpaperWebUIEnabled();
   }
 #else
   return false;
diff --git a/chrome/build/OWNERS b/chrome/build/OWNERS
index 56289de..cebb5613 100644
--- a/chrome/build/OWNERS
+++ b/chrome/build/OWNERS
@@ -1,2 +1,11 @@
 liaoyuke@chromium.org
 sebmarchand@chromium.org
+
+per-file linux.pgo.txt=chromium-autoroll@skia-public.iam.gserviceaccount.com
+per-file linux.pgo.txt=chromium-release-autoroll@skia-public.iam.gserviceaccount.com
+per-file mac.pgo.txt=chromium-autoroll@skia-public.iam.gserviceaccount.com
+per-file mac.pgo.txt=chromium-release-autoroll@skia-public.iam.gserviceaccount.com
+per-file win32.pgo.txt=chromium-autoroll@skia-public.iam.gserviceaccount.com
+per-file win32.pgo.txt=chromium-release-autoroll@skia-public.iam.gserviceaccount.com
+per-file win64.pgo.txt=chromium-autoroll@skia-public.iam.gserviceaccount.com
+per-file win64.pgo.txt=chromium-release-autoroll@skia-public.iam.gserviceaccount.com
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 3d3511e..c038d6061 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1616003779-9d74256b5a2600ba4439134b7ce065bd2ac4a75c.profdata
+chrome-linux-master-1616025579-099738fd3321a1cdf283d620e0123d6bdd73b9ba.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 0e5e9432..59bda8f 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1616003779-c43fade97bfa9228555ce027ef6b650a0ec5e85a.profdata
+chrome-mac-master-1616025579-0d2a5bc17304c4b26bf0316d5e5e74495d0c8f96.profdata
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index c00a160..8c4b44b 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -202,6 +202,7 @@
         "$root_gen_dir/chromeos/chromeos_help_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_media_app_bundle_resources.pak",
         "$root_gen_dir/chromeos/chromeos_media_app_resources.pak",
+        "$root_gen_dir/chromeos/chromeos_personalization_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_print_management_resources.pak",
         "$root_gen_dir/chromeos/chromeos_resources.pak",
         "$root_gen_dir/chromeos/chromeos_scanning_app_resources.pak",
@@ -233,6 +234,7 @@
         "//chromeos/resources:help_app_resources",
         "//chromeos/resources:media_app_bundle_resources",
         "//chromeos/resources:media_app_resources",
+        "//chromeos/resources:personalization_app_resources",
         "//chromeos/resources:print_management_resources",
         "//chromeos/resources:scanning_app_resources",
         "//ui/file_manager:file_manager_gen_resources",
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json
index 20b1199..4da0fe23 100644
--- a/chrome/common/extensions/api/accessibility_private.json
+++ b/chrome/common/extensions/api/accessibility_private.json
@@ -596,6 +596,36 @@
           }
         ],
         "platforms": ["chromeos"]
+      },
+      {
+        "name": "showConfirmationDialog",
+        "type": "function",
+        "description": "Shows a confirmation dialog.",
+        "parameters": [
+          {
+            "name": "title",
+            "type": "string",
+            "description": "The title of the confirmation dialog."
+          },
+          {
+            "name": "description",
+            "type": "string",
+            "description": "The description to show within the confirmation dialog."
+          },
+          {
+            "name": "callback",
+            "type": "function",
+            "description": "Called when the dialog is confirmed or cancelled.",
+            "parameters": [
+              {
+                "type": "boolean",
+                "name": "confirmed",
+                "description": "True if the dialog was confirmed, false if it was canceled or closed."
+              }
+            ]
+          }
+        ],
+        "platforms": ["chromeos"]
       }
     ],
     "events": [
diff --git a/chrome/common/extensions/api/common_extension_api_unittest.cc b/chrome/common/extensions/api/common_extension_api_unittest.cc
index bbd6851..68dd6dc 100644
--- a/chrome/common/extensions/api/common_extension_api_unittest.cc
+++ b/chrome/common/extensions/api/common_extension_api_unittest.cc
@@ -470,9 +470,9 @@
   }
 
   std::string error;
-  scoped_refptr<Extension> extension(Extension::Create(
-      base::FilePath(), Manifest::UNPACKED,
-      manifest, Extension::NO_FLAGS, &error));
+  scoped_refptr<Extension> extension(
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kUnpacked,
+                        manifest, Extension::NO_FLAGS, &error));
   CHECK(extension.get());
   CHECK(error.empty());
 
@@ -551,9 +551,9 @@
   values.SetString(manifest_keys::kLaunchWebURL,
                    "http://www.example.com");
   std::string error;
-  scoped_refptr<Extension> extension(Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, values, Extension::NO_FLAGS,
-      &error));
+  scoped_refptr<Extension> extension(
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                        values, Extension::NO_FLAGS, &error));
   CHECK(extension.get());
   return extension;
 }
@@ -582,9 +582,9 @@
   }
 
   std::string error;
-  scoped_refptr<Extension> extension(Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, values, Extension::NO_FLAGS,
-      &error));
+  scoped_refptr<Extension> extension(
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                        values, Extension::NO_FLAGS, &error));
   CHECK(extension.get()) << error;
   return extension;
 }
diff --git a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
index 115e308..553890c 100644
--- a/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
+++ b/chrome/common/extensions/api/storage/storage_schema_manifest_handler_unittest.cc
@@ -37,9 +37,9 @@
 
   scoped_refptr<Extension> CreateExtension(const std::string& schema) {
     std::string error;
-    scoped_refptr<Extension> extension =
-        Extension::Create(temp_dir_.GetPath(), Manifest::UNPACKED, manifest_,
-                          Extension::NO_FLAGS, "", &error);
+    scoped_refptr<Extension> extension = Extension::Create(
+        temp_dir_.GetPath(), mojom::ManifestLocation::kUnpacked, manifest_,
+        Extension::NO_FLAGS, "", &error);
     if (!extension.get())
       return nullptr;
     base::FilePath schema_path = temp_dir_.GetPath().AppendASCII("schema.json");
diff --git a/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc b/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc
index 458d678..d129973 100644
--- a/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc
+++ b/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc
@@ -25,9 +25,9 @@
   std::vector<InstallWarning> warnings;
   base::ScopedTempDir dir;
   ASSERT_TRUE(dir.CreateUniqueTempDir());
-  scoped_refptr<Extension> extension =
-      Extension::Create(dir.GetPath(), Manifest::INTERNAL, *manifest_value,
-                        Extension::NO_FLAGS, std::string(), &error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      dir.GetPath(), mojom::ManifestLocation::kInternal, *manifest_value,
+      Extension::NO_FLAGS, std::string(), &error);
   ASSERT_TRUE(extension);
   EXPECT_FALSE(
       file_util::ValidateExtension(extension.get(), &error, &warnings));
diff --git a/chrome/common/extensions/extension_test_util.cc b/chrome/common/extensions/extension_test_util.cc
index d0474a2d..0b7458d9 100644
--- a/chrome/common/extensions/extension_test_util.cc
+++ b/chrome/common/extensions/extension_test_util.cc
@@ -45,7 +45,9 @@
   CHECK(result->GetAsDictionary(&dict));
 
   scoped_refptr<Extension> extension = Extension::Create(
-      path.DirName(), location, *dict, extra_flags, id, error);
+      path.DirName(),
+      static_cast<extensions::mojom::ManifestLocation>(location), *dict,
+      extra_flags, id, error);
   return extension;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
index fefc4ec..7a7ecf6 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
@@ -113,9 +113,10 @@
 
 scoped_refptr<Extension> CreateExtension(const base::DictionaryValue& manifest,
                                          std::string* error) {
-  scoped_refptr<Extension> extension = Extension::Create(
-      base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
-      Manifest::INVALID_LOCATION, manifest, Extension::NO_FLAGS, error);
+  scoped_refptr<Extension> extension =
+      Extension::Create(base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+                        extensions::mojom::ManifestLocation::kInvalidLocation,
+                        manifest, Extension::NO_FLAGS, error);
   return extension;
 }
 
diff --git a/chrome/common/extensions/manifest_unittest.cc b/chrome/common/extensions/manifest_unittest.cc
index f43acfa..f51d59d 100644
--- a/chrome/common/extensions/manifest_unittest.cc
+++ b/chrome/common/extensions/manifest_unittest.cc
@@ -71,7 +71,8 @@
     ExtensionId extension_id = manifest->get()->extension_id();
     if (for_login_screen) {
       *manifest = Manifest::CreateManifestForLoginScreen(
-          Manifest::EXTERNAL_POLICY, std::move(manifest_value), extension_id);
+          mojom::ManifestLocation::kExternalPolicy, std::move(manifest_value),
+          extension_id);
     } else {
       *manifest = std::make_unique<Manifest>(
           Manifest::INTERNAL, std::move(manifest_value), extension_id);
diff --git a/chrome/common/extensions/sync_type_unittest.cc b/chrome/common/extensions/sync_type_unittest.cc
index 2150a48..ef8daca 100644
--- a/chrome/common/extensions/sync_type_unittest.cc
+++ b/chrome/common/extensions/sync_type_unittest.cc
@@ -32,7 +32,7 @@
       SyncTestExtensionType type,
       const GURL& update_url,
       const GURL& launch_url,
-      Manifest::Location location,
+      mojom::ManifestLocation location,
       const base::FilePath& extension_path,
       int creation_flags) {
     base::DictionaryValue source;
@@ -70,10 +70,9 @@
     "https://clients2.google.com/service/update2/crx";
 
 TEST_F(ExtensionSyncTypeTest, NormalExtensionNoUpdateUrl) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
 }
@@ -81,26 +80,24 @@
 TEST_F(ExtensionSyncTypeTest, UserScriptValidUpdateUrl) {
   scoped_refptr<Extension> extension(
       MakeSyncTestExtension(USER_SCRIPT, GURL(kValidUpdateUrl1), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+                            mojom::ManifestLocation::kInternal,
+                            base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, UserScriptNoUpdateUrl) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(USER_SCRIPT, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      USER_SCRIPT, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, ThemeNoUpdateUrl) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(THEME, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      THEME, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_theme());
   EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
 }
@@ -108,43 +105,41 @@
 TEST_F(ExtensionSyncTypeTest, AppWithLaunchUrl) {
   scoped_refptr<Extension> extension(
       MakeSyncTestExtension(EXTENSION, GURL(), GURL("http://www.google.com"),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+                            mojom::ManifestLocation::kInternal,
+                            base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_app());
   EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, ExtensionExternal) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::EXTERNAL_PREF, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kExternalPref,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, UserScriptThirdPartyUpdateUrl) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(
-          USER_SCRIPT, GURL("http://third-party.update_url.com"), GURL(),
-          Manifest::INTERNAL, base::FilePath(), Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      USER_SCRIPT, GURL("http://third-party.update_url.com"), GURL(),
+      mojom::ManifestLocation::kInternal, base::FilePath(),
+      Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, OnlyDisplayAppsInLauncher) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
 
   EXPECT_FALSE(extension->ShouldDisplayInAppLauncher());
   EXPECT_FALSE(extension->ShouldDisplayInNewTabPage());
 
   scoped_refptr<Extension> app(
       MakeSyncTestExtension(APP, GURL(), GURL("http://www.google.com"),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+                            mojom::ManifestLocation::kInternal,
+                            base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
   EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
 }
@@ -160,24 +155,24 @@
   scoped_refptr<Extension> app;
 
   // Default to true.
-  app = Extension::Create(
-      base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+  app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
+                          manifest, 0, &error);
   EXPECT_EQ(error, std::string());
   EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
   EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
 
   // Value display_in_NTP defaults to display_in_launcher.
   manifest.SetBoolean(keys::kDisplayInLauncher, false);
-  app = Extension::Create(
-      base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+  app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
+                          manifest, 0, &error);
   EXPECT_EQ(error, std::string());
   EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
   EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
 
   // Value display_in_NTP = true overriding display_in_launcher = false.
   manifest.SetBoolean(keys::kDisplayInNewTabPage, true);
-  app = Extension::Create(
-      base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+  app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
+                          manifest, 0, &error);
   EXPECT_EQ(error, std::string());
   EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
   EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
@@ -185,45 +180,42 @@
   // Value display_in_NTP = false only, overrides default = true.
   manifest.Remove(keys::kDisplayInLauncher, NULL);
   manifest.SetBoolean(keys::kDisplayInNewTabPage, false);
-  app = Extension::Create(
-      base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+  app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
+                          manifest, 0, &error);
   EXPECT_EQ(error, std::string());
   EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
   EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
 
   // Error checking.
   manifest.SetString(keys::kDisplayInNewTabPage, "invalid");
-  app = Extension::Create(
-      base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+  app = Extension::Create(base::FilePath(), mojom::ManifestLocation::kComponent,
+                          manifest, 0, &error);
   EXPECT_EQ(error, std::string(errors::kInvalidDisplayInNewTabPage));
 }
 
 TEST_F(ExtensionSyncTypeTest, OnlySyncInternal) {
-  scoped_refptr<Extension> extension_internal(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension_internal(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(sync_helper::IsSyncable(extension_internal.get()));
 
-  scoped_refptr<Extension> extension_noninternal(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::COMPONENT, base::FilePath(),
-                            Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension_noninternal(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kComponent,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_FALSE(sync_helper::IsSyncable(extension_noninternal.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, DontSyncDefault) {
-  scoped_refptr<Extension> extension_default(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
-                            Manifest::INTERNAL, base::FilePath(),
-                            Extension::WAS_INSTALLED_BY_DEFAULT));
+  scoped_refptr<Extension> extension_default(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::WAS_INSTALLED_BY_DEFAULT));
   EXPECT_FALSE(sync_helper::IsSyncable(extension_default.get()));
 }
 
 TEST_F(ExtensionSyncTypeTest, DontSyncExtensionInDoNotSyncList) {
-  scoped_refptr<Extension> extension(
-      MakeSyncTestExtension(EXTENSION, GURL(), GURL(), Manifest::INTERNAL,
-                            base::FilePath(), Extension::NO_FLAGS));
+  scoped_refptr<Extension> extension(MakeSyncTestExtension(
+      EXTENSION, GURL(), GURL(), mojom::ManifestLocation::kInternal,
+      base::FilePath(), Extension::NO_FLAGS));
   EXPECT_TRUE(extension->is_extension());
   EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
   SimpleFeature::ScopedThreadUnsafeAllowlistForTest allowlist(extension->id());
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc
index 8c9dfe7..78f7004 100644
--- a/chrome/renderer/chrome_content_renderer_client_unittest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -47,6 +47,10 @@
 using content::WebPluginInfo;
 using content::WebPluginMimeType;
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+using extensions::mojom::ManifestLocation;
+#endif
+
 namespace {
 
 #if BUILDFLAG(ENABLE_NACL)
@@ -90,8 +94,10 @@
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 scoped_refptr<const extensions::Extension> CreateTestExtension(
-    extensions::Manifest::Location location, bool is_from_webstore,
-    bool is_hosted_app, const std::string& app_url) {
+    ManifestLocation location,
+    bool is_from_webstore,
+    bool is_hosted_app,
+    const std::string& app_url) {
   int flags = is_from_webstore ?
       extensions::Extension::FROM_WEBSTORE:
       extensions::Extension::NO_FLAGS;
@@ -113,23 +119,21 @@
 
 scoped_refptr<const extensions::Extension> CreateExtension(
     bool is_from_webstore) {
-  return CreateTestExtension(
-      extensions::Manifest::INTERNAL, is_from_webstore, kNotHostedApp,
-      std::string());
+  return CreateTestExtension(ManifestLocation::kInternal, is_from_webstore,
+                             kNotHostedApp, std::string());
 }
 
 scoped_refptr<const extensions::Extension> CreateExtensionWithLocation(
-    extensions::Manifest::Location location, bool is_from_webstore) {
+    ManifestLocation location,
+    bool is_from_webstore) {
   return CreateTestExtension(
       location, is_from_webstore, kNotHostedApp, std::string());
 }
 
 scoped_refptr<const extensions::Extension> CreateHostedApp(
     bool is_from_webstore, const std::string& app_url) {
-  return CreateTestExtension(extensions::Manifest::INTERNAL,
-                             is_from_webstore,
-                             kHostedApp,
-                             app_url);
+  return CreateTestExtension(ManifestLocation::kInternal, is_from_webstore,
+                             kHostedApp, app_url);
 }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
@@ -160,7 +164,7 @@
   {
     EXPECT_TRUE(ChromeContentRendererClient::IsNativeNaClAllowed(
         GURL(kExtensionUrl), kNaClRestricted,
-        CreateExtensionWithLocation(extensions::Manifest::UNPACKED,
+        CreateExtensionWithLocation(ManifestLocation::kUnpacked,
                                     kExtensionNotFromWebStore)
             .get()));
   }
@@ -168,14 +172,14 @@
   {
     EXPECT_TRUE(ChromeContentRendererClient::IsNativeNaClAllowed(
         GURL(kExtensionUrl), kNaClRestricted,
-        CreateExtensionWithLocation(extensions::Manifest::COMPONENT,
+        CreateExtensionWithLocation(ManifestLocation::kComponent,
                                     kExtensionNotFromWebStore)
             .get()));
   }
   {
     EXPECT_TRUE(ChromeContentRendererClient::IsNativeNaClAllowed(
         GURL(kExtensionUrl), kNaClRestricted,
-        CreateExtensionWithLocation(extensions::Manifest::EXTERNAL_COMPONENT,
+        CreateExtensionWithLocation(ManifestLocation::kExternalComponent,
                                     kExtensionNotFromWebStore)
             .get()));
   }
@@ -184,14 +188,13 @@
   {
     EXPECT_TRUE(ChromeContentRendererClient::IsNativeNaClAllowed(
         GURL(kExtensionUrl), kNaClRestricted,
-        CreateExtensionWithLocation(extensions::Manifest::EXTERNAL_POLICY,
+        CreateExtensionWithLocation(ManifestLocation::kExternalPolicy,
                                     kExtensionNotFromWebStore)
             .get()));
     EXPECT_TRUE(ChromeContentRendererClient::IsNativeNaClAllowed(
         GURL(kExtensionUrl), kNaClRestricted,
-        CreateExtensionWithLocation(
-            extensions::Manifest::EXTERNAL_POLICY_DOWNLOAD,
-            kExtensionNotFromWebStore)
+        CreateExtensionWithLocation(ManifestLocation::kExternalPolicyDownload,
+                                    kExtensionNotFromWebStore)
             .get()));
   }
   // CWS extensions are allowed without --enable-nacl if called from an
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index b1155c7..b690e14 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2191,7 +2191,6 @@
 
       if (is_chromeos_ash) {
         sources += [
-          "../browser/accessibility/accessibility_extension_api_browsertest.cc",
           "../browser/apps/platform_apps/api/arc_apps_private/arc_apps_private_apitest.cc",
           "../browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest_chromeos.cc",
           "../browser/extensions/api/crash_report_private/crash_report_private_apitest.cc",
@@ -2440,6 +2439,7 @@
         "../browser/apps/platform_apps/app_window_interactive_uitest_base.cc",
         "../browser/apps/platform_apps/app_window_interactive_uitest_base.h",
         "../browser/ash/accessibility/accessibility_common_browsertest.cc",
+        "../browser/ash/accessibility/accessibility_extension_api_browsertest.cc",
         "../browser/ash/accessibility/accessibility_manager_browsertest.cc",
         "../browser/ash/accessibility/accessibility_test_utils.cc",
         "../browser/ash/accessibility/accessibility_test_utils.h",
@@ -2461,6 +2461,10 @@
         "../browser/ash/app_mode/web_app/web_kiosk_app_data_browsertest.cc",
         "../browser/ash/apps/apk_web_app_installer_browsertest.cc",
         "../browser/ash/attestation/attestation_policy_browsertest.cc",
+        "../browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc",
+        "../browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc",
+        "../browser/ash/arc/auth/arc_auth_service_browsertest.cc",
+        "../browser/ash/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc",
         "../browser/ash/login/accessibility_browsertest.cc",
         "../browser/ash/login/active_directory_login_browsertest.cc",
         "../browser/ash/login/app_mode/auto_launched_kiosk_browsertest.cc",
@@ -2621,10 +2625,6 @@
         "../browser/ash/web_applications/system_web_app_integration_test.cc",
         "../browser/ash/web_applications/system_web_app_integration_test.h",
         "../browser/chrome_main_browsertest.cc",
-        "../browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc",
-        "../browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc",
-        "../browser/chromeos/arc/auth/arc_auth_service_browsertest.cc",
-        "../browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc",
         "../browser/chromeos/arc/enterprise/cert_store/cert_store_service_browsertest.cc",
         "../browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc",
         "../browser/chromeos/arc/intent_helper/custom_tab_session_impl_browsertest.cc",
@@ -2684,7 +2684,6 @@
         "../browser/chromeos/file_manager/devtools_listener.h",
         "../browser/chromeos/file_manager/devtools_listener_browsertest.cc",
         "../browser/chromeos/file_manager/external_filesystem_apitest.cc",
-        "../browser/chromeos/file_manager/file_manager_base_jstest.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest_base.cc",
         "../browser/chromeos/file_manager/file_manager_browsertest_base.h",
@@ -4437,6 +4436,7 @@
       "../browser/password_manager/android/update_password_infobar_delegate_android_unittest.cc",
       "../browser/permissions/permission_prompt_android_unittest.cc",
       "../browser/profiles/android/profile_resolver_unittest.cc",
+      "../browser/sharing/sms/sms_fetch_request_handler_unittest.cc",
       "../browser/touch_to_fill/touch_to_fill_controller_unittest.cc",
       "../browser/translate/translate_manager_render_view_host_android_unittest.cc",
     ]
@@ -4671,6 +4671,7 @@
       "../browser/ui/extensions/extension_installed_waiter_unittest.cc",
       "../browser/ui/extensions/extension_message_bubble_bridge_unittest.cc",
       "../browser/ui/extensions/extension_settings_overridden_dialog_unittest.cc",
+      "../browser/ui/extensions/settings_api_bubble_helpers_unittest.cc",
       "../browser/ui/extensions/settings_overridden_params_providers_unittest.cc",
       "../browser/ui/font_access/font_access_chooser_controller_unittest.cc",
       "../browser/ui/global_error/global_error_service_unittest.cc",
@@ -4930,7 +4931,6 @@
       "../browser/sharing/shared_clipboard/shared_clipboard_test_base.h",
       "../browser/sharing/shared_clipboard/shared_clipboard_ui_controller_unittest.cc",
       "../browser/sharing/shared_clipboard/shared_clipboard_utils_unittest.cc",
-      "../browser/sharing/sms/sms_fetch_request_handler_unittest.cc",
       "../browser/sharing/sms/sms_remote_fetcher_unittest.cc",
       "../browser/ui/autofill/payments/local_card_migration_bubble_controller_impl_unittest.cc",
       "../browser/ui/autofill/payments/offer_notification_bubble_controller_impl_unittest.cc",
@@ -5413,7 +5413,6 @@
       "../browser/extensions/installed_loader_unittest.cc",
       "../browser/extensions/media_router_extension_access_logger_impl_unittest.cc",
       "../browser/extensions/menu_manager_unittest.cc",
-      "../browser/extensions/ntp_overridden_bubble_delegate_unittest.cc",
       "../browser/extensions/pack_extension_unittest.cc",
       "../browser/extensions/permission_message_combinations_unittest.cc",
       "../browser/extensions/permission_messages_unittest.cc",
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.html b/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.html
new file mode 100644
index 0000000..496c8eb
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.html
@@ -0,0 +1,7 @@
+<!--
+ * Copyright 2021 The Chromium Authors. All rights reserved.  Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<meta charset="utf-16">
+<script src="accept_confirmation_dialog.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.js b/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.js
new file mode 100644
index 0000000..6527fa7
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/accept_confirmation_dialog.js
@@ -0,0 +1,14 @@
+// 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.
+
+chrome.accessibilityPrivate.showConfirmationDialog(
+    'Confirm me! 🐶', 'This dialog should be confirmed.', (confirmed) => {
+      if (confirmed) {
+        chrome.test.succeed();
+      } else {
+        chrome.test.fail();
+      }
+    });
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.html b/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.html
new file mode 100644
index 0000000..41e33dcd
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright 2021 The Chromium Authors. All rights reserved.  Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="cancel_confirmation_dialog.js"></script>
diff --git a/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.js b/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.js
new file mode 100644
index 0000000..f63bfdc0
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/accessibility_private/cancel_confirmation_dialog.js
@@ -0,0 +1,14 @@
+// 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.
+
+chrome.accessibilityPrivate.showConfirmationDialog(
+    'Cancel me!', 'This dialog should be canceled', (confirmed) => {
+      if (confirmed) {
+        chrome.test.fail();
+      } else {
+        chrome.test.succeed();
+      }
+    });
+
+chrome.test.notifyPass();
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index ce08268..280c952 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -44,7 +44,6 @@
     data = [
       "$root_gen_dir/chrome/test/data/webui/fake_chrome_event.m.js",
       "$root_gen_dir/chrome/test/data/webui/mock_controller.m.js",
-      "$root_gen_dir/chrome/test/data/webui/settings/test_sync_browser_proxy.m.js",
       "$root_gen_dir/chrome/test/data/webui/test_browser_proxy.m.js",
       "$root_gen_dir/chrome/test/data/webui/test_store.m.js",
       "$root_gen_dir/chrome/test/data/webui/test_util.m.js",
diff --git a/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js b/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
index 32b13b7..652a7a8 100644
--- a/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
+++ b/chrome/test/data/webui/chromeos/crostini_upgrader_browsertest.js
@@ -17,8 +17,6 @@
 
   browsePreload:
       'chrome://crostini-upgrader/test_loader.html?module=chromeos/crostini_upgrader_app_test.js',
-
-  featureList: {enabled: ['chromeos::features::kCrostiniWebUIUpgrader']},
 };
 
 
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js
index ee03b6a..2a02932 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/activation_code_page_test.js
@@ -27,21 +27,22 @@
     return new Promise(resolve => setTimeout(resolve));
   }
 
-  setup(function() {
-    activationCodePage = document.createElement('activation-code-page');
+  // Captures the function that is called every time the interval timer
+  // timeouts.
+  function setIntervalFunction(fn, milliseconds) {
+    intervalFunction = fn;
+    return 1;
+  }
 
-    // Captures the function that is called every time the interval timer
-    // timeouts.
-    const setIntervalFunction = (fn, milliseconds) => {
-      intervalFunction = fn;
-      return 1;
-    };
-    // In tests, pausing the video can have race conditions with previous
-    // requests to play the video due to the speed of execution. Avoid this by
-    // mocking the play and pause actions.
-    const playVideoFunction = () => {};
-    const stopStreamFunction = (stream) => {};
-    activationCodePage.setFakesForTesting(
+  // In tests, pausing the video can have race conditions with previous
+  // requests to play the video due to the speed of execution. Avoid this by
+  // mocking the play and pause actions.
+  function playVideoFunction() {}
+  function stopStreamFunction(stream) {}
+
+  setup(async function() {
+    activationCodePage = document.createElement('activation-code-page');
+    await activationCodePage.setFakesForTesting(
         FakeBarcodeDetector, FakeImageCapture, setIntervalFunction,
         playVideoFunction, stopStreamFunction);
     document.body.appendChild(activationCodePage);
@@ -284,9 +285,9 @@
         assertTrue(!!qrCodeDetectorContainer);
 
         FakeBarcodeDetector.setShouldFail(true);
-        activationCodePage.initBarcodeDetector();
-
-        await flushAsync();
+        await activationCodePage.setFakesForTesting(
+            FakeBarcodeDetector, FakeImageCapture, setIntervalFunction,
+            playVideoFunction, stopStreamFunction);
 
         qrCodeDetectorContainer = activationCodePage.$$('#esimQrCodeDetection');
 
diff --git a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
index b7f0a21..5795b23 100644
--- a/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/cellular_setup/esim_flow_ui_test.js
@@ -13,7 +13,7 @@
 // #import {assertEquals, assertTrue} from '../../../chai_assert.js';
 // #import {FakeESimManagerRemote} from './fake_esim_manager_remote.m.js';
 // #import {FakeCellularSetupDelegate} from './fake_cellular_setup_delegate.m.js';
-// #import {FakeBarcodeDetector} from './fake_barcode_detector.m.js';
+// #import {FakeBarcodeDetector, FakeImageCapture} from './fake_barcode_detector.m.js';
 // #import {FakeNetworkConfig} from 'chrome://test/chromeos/fake_network_config_mojom.m.js';
 // #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js';
 // #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js';
@@ -95,9 +95,6 @@
     const availableEuiccs = await eSimManagerRemote.getAvailableEuiccs();
     const euicc = availableEuiccs.euiccs[0];
 
-    activationCodePage.barcodeDetectorClass_ = FakeBarcodeDetector;
-    activationCodePage.initBarcodeDetector();
-
     euicc.setRequestPendingProfilesResult(
         chromeos.cellularSetup.mojom.ESimOperationResult.kFailure);
     eSimPage.initSubflow();
@@ -106,7 +103,7 @@
     endFlowAndVerifyResult(ESimSetupFlowResult.ERROR_FETCHING_PROFILES);
   });
 
-  setup(function() {
+  setup(async function() {
     networkConfigRemote = new FakeNetworkConfig();
 
     addOnlineWifiNetwork();
@@ -131,6 +128,22 @@
     confirmationCodePage = eSimPage.$$('#confirmationCodePage');
     finalPage = eSimPage.$$('#finalPage');
 
+    // Captures the function that is called every time the interval timer
+    // timeouts.
+    const setIntervalFunction = (fn, milliseconds) => {
+      intervalFunction = fn;
+      return 1;
+    };
+
+    // In tests, pausing the video can have race conditions with previous
+    // requests to play the video due to the speed of execution. Avoid this by
+    // mocking the play and pause actions.
+    const playVideoFunction = () => {};
+    const stopStreamFunction = (stream) => {};
+    await activationCodePage.setFakesForTesting(
+        FakeBarcodeDetector, FakeImageCapture, setIntervalFunction,
+        playVideoFunction, stopStreamFunction);
+
     assertTrue(!!profileLoadingPage);
     assertTrue(!!profileDiscoveryPage);
     assertTrue(!!activationCodePage);
@@ -258,8 +271,6 @@
       const availableEuiccs = await eSimManagerRemote.getAvailableEuiccs();
       euicc = availableEuiccs.euiccs[0];
 
-      activationCodePage.barcodeDetectorClass_ = FakeBarcodeDetector;
-      activationCodePage.initBarcodeDetector();
       await flushAsync();
       eSimPage.initSubflow();
 
@@ -274,12 +285,7 @@
       assertActivationCodePage(/*forwardButtonShouldBeEnabled=*/ true);
     });
 
-    // TODO(crbug.com/1188665) Renable flaky test
-    test.skip('Invalid activation code', async function() {
-      activationCodePage.barcodeDetectorClass_ = FakeBarcodeDetector;
-      activationCodePage.initBarcodeDetector();
-      await flushAsync();
-
+    test('Invalid activation code', async function() {
       euicc.setProfileInstallResultForTest(
           chromeos.cellularSetup.mojom.ProfileInstallResult
               .kErrorInvalidActivationCode);
@@ -288,8 +294,7 @@
 
       // Install should fail and still be at activation code page.
       assertActivationCodePage(/*forwardButtonShouldBeEnabled=*/ true);
-      assertTrue(activationCodePage.$$('#scanSuccessContainer').hidden);
-      assertFalse(activationCodePage.$$('#scanFailureContainer').hidden);
+      assertTrue(activationCodePage.showError);
 
       endFlowAndVerifyResult(
           ESimSetupFlowResult.CANCELLED_INVALID_ACTIVATION_CODE);
diff --git a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
index 605f0f1..e1e0dea 100644
--- a/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
+++ b/chrome/test/data/webui/cr_components/chromeos/network/network_config_test.js
@@ -236,6 +236,26 @@
       });
     });
 
+    test('New Config: Authenticated, Not secure to secure', async function() {
+      // set default to insecure network
+      setNetworkType(chromeos.networkConfig.mojom.NetworkType.kWiFi);
+      setAuthenticated();
+      initNetworkConfig();
+      await flushAsync();
+      let share = networkConfig.$$('#share');
+      assertTrue(!!share);
+      assertTrue(share.disabled);
+      assertTrue(share.checked);
+
+      // change to secure network
+      networkConfig.securityType_ =
+          chromeos.networkConfig.mojom.SecurityType.kWepPsk;
+      await flushAsync();
+      assertTrue(!!share);
+      assertFalse(share.disabled);
+      assertFalse(share.checked);
+    });
+
     // Existing networks hide the shared control in the config UI.
     test('Existing Hides Shared', function() {
       const wifi1 = OncMojo.getDefaultManagedProperties(
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_basic_viewport_scale.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_basic_viewport_scale.html
new file mode 100644
index 0000000..b533670
--- /dev/null
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_basic_viewport_scale.html
@@ -0,0 +1,180 @@
+<!--
+Tests for WebXR dynamic viewport scaling.
+-->
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
+  </head>
+  <body>
+    <canvas id="webgl-canvas"></canvas>
+    <script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
+    <script src="../resources/webxr_e2e.js"></script>
+    <script>var shouldAutoCreateNonImmersiveSession = false;</script>
+    <script src="../resources/webxr_boilerplate.js"></script>
+    <script>
+      setup({single_test: true});
+
+      // Tests that requesting a viewport scale takes effect immediately if done
+      // before calling getViewport.
+      function stepRequestViewportScaleSameFrame() {
+        let sessionInfo = sessionInfos[sessionTypes.AR];
+        const referenceSpace = sessionInfo.currentRefSpace;
+        const session = sessionInfo.currentSession;
+
+        let frameCount = 0;
+
+        onARFrameCallback = (session, frame) => {
+          const pose = frame.getViewerPose(referenceSpace);
+          const baseLayer = session.renderState.baseLayer;
+          const framebufferPixels = baseLayer.framebufferWidth * baseLayer.framebufferHeight;
+          let viewportPixels = 0;
+          for (const view of pose.views) {
+            view.requestViewportScale(frameCount > 0 ? 0.5 : 1.0);
+            let viewport = baseLayer.getViewport(view);
+            viewportPixels += viewport.width * viewport.height;
+
+            // Draw something to the framebuffer to ensure that the driver side applies the buffer size.
+            gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer);
+            gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+            gl.clearColor(0.0, 0.0, 1.0, 0.5);
+            gl.clear(gl.COLOR_BUFFER_BIT);
+          }
+          assert_greater_than(viewportPixels, 0);
+          assert_less_than_equal(viewportPixels, framebufferPixels);
+          if (frameCount == 0) {
+            // For the ARCore device, assume that the default viewport entirely fills
+            // the framebuffer. This isn't required by the spec, so this check may
+            // need to be changed for other devices that don't do this.
+            assert_equals(viewportPixels, framebufferPixels);
+          } else {
+            assert_less_than(viewportPixels, framebufferPixels);
+            done();
+          }
+          ++frameCount;
+        };
+      }
+
+      // Tests that requesting a viewport scale after a preceding getViewport call takes
+      // effect on the next animation frame, keeping the viewport consistent within a frame.
+      function stepRequestViewportScaleNextFrame() {
+        let sessionInfo = sessionInfos[sessionTypes.AR];
+        const referenceSpace = sessionInfo.currentRefSpace;
+        const session = sessionInfo.currentSession;
+
+        let appliedViewportScaleSameFrame = false;
+        let frameCount = 0;
+
+        onARFrameCallback = (session, frame) => {
+          const pose = frame.getViewerPose(referenceSpace);
+          const baseLayer = session.renderState.baseLayer;
+          const framebufferPixels = baseLayer.framebufferWidth * baseLayer.framebufferHeight;
+          let viewportPixels = 0;
+          for (const view of pose.views) {
+            // Call getViewport first before requesting a viewport scale. This locks in
+            // the size for the current animation frame.
+            const viewportA = baseLayer.getViewport(view);
+            viewportPixels += viewportA.width * viewportA.height;
+
+            // Request a size to apply to the next frame.
+            view.requestViewportScale(frameCount > 0 ? 0.5 : 1.0);
+
+            // Calling getViewport again must return the same size as the earlier call.
+            const viewportB = baseLayer.getViewport(view);
+            assert_equals(viewportA.width, viewportB.width);
+            assert_equals(viewportA.height, viewportB.height);
+
+            // Draw something to the framebuffer to ensure that the driver side applies the buffer size.
+            gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer);
+            gl.viewport(viewportA.x, viewportA.y, viewportA.width, viewportA.height);
+            gl.clearColor(0.0, 0.0, 1.0, 0.5);
+            gl.clear(gl.COLOR_BUFFER_BIT);
+          }
+          assert_greater_than(viewportPixels, 0);
+          assert_less_than_equal(viewportPixels, framebufferPixels);
+          if (frameCount == 1) {
+            assert_equals(viewportPixels, framebufferPixels);
+          } else if (frameCount > 1) {
+            assert_less_than(viewportPixels, framebufferPixels);
+            done();
+          }
+          ++frameCount;
+        };
+      }
+
+      // Tests that the recommendedViewportScale exists, is reduced when GPU load increases, then
+      // increases again when load is low.
+      function stepRequestRecommendedViewportScale() {
+        let sessionInfo = sessionInfos[sessionTypes.AR];
+        const referenceSpace = sessionInfo.currentRefSpace;
+        const session = sessionInfo.currentSession;
+
+        let gotAnyRecommendedViewportScale = false;
+        let gotReducedRecommendedViewportScale = false;
+        let gotIncreasedRecommendedViewportScale = false;
+        let clearRectangleCount = 1;
+        let minViewportScale = 99999;
+
+        onARFrameCallback = (session, frame) => {
+          const pose = frame.getViewerPose(referenceSpace);
+          gl.enable(gl.SCISSOR_TEST);
+          for (const view of pose.views) {
+            const recScale = view.recommendedViewportScale;
+            if (recScale) {
+              if (recScale > 0) {
+                gotAnyRecommendedViewportScale = true;
+              }
+              if (gotReducedRecommendedViewportScale) {
+                if (recScale > minViewportScale) {
+                  if (!gotIncreasedRecommendedViewportScale) {
+                    // Only log the increase once - the session may not terminate immediately after calling done().
+                    console.log("got recommendedViewportScale increase from " + minViewportScale + " to " + recScale);
+                  }
+                  gotIncreasedRecommendedViewportScale = true;
+                }
+              } else {
+                if (recScale < 1.0) {
+                  gotReducedRecommendedViewportScale = true;
+                  minViewportScale=Math.min(minViewportScale, recScale);
+                  console.log("got recommendedViewportScale=" + recScale + " at clearRectangleCount=" + clearRectangleCount);
+                }
+              }
+            }
+
+            view.requestViewportScale(view.recommendedViewportScale);
+
+            const baseLayer = session.renderState.baseLayer;
+            let viewport = baseLayer.getViewport(view);
+
+            // Draw an exponentially increasing number of translucent rectangles to stress the GPU
+            // and trigger a decrease of the recommended viewport size. Once the viewport size
+            // decreased, revert back to a single rectangle and wait for the size to increase
+            // again.
+            gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer);
+            gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
+            for (let i = 0; i < clearRectangleCount; ++i) {
+              const xOffset = viewport.width * Math.random() / 2;
+              const yOffset = viewport.height * Math.random() / 2;
+              gl.scissor(viewport.x + xOffset, viewport.y + yOffset, viewport.width / 2, viewport.height / 2);
+              gl.clearColor(Math.random(), Math.random(), Math.random(), Math.random() / 2);
+              gl.clear(gl.COLOR_BUFFER_BIT);
+            }
+            if (gotReducedRecommendedViewportScale) {
+              // Done with the load test, wait for size to increase again.
+              clearRectangleCount = 1;
+            } else {
+              // Add more load.
+              clearRectangleCount *= 2;
+            }
+          }
+          gl.disable(gl.SCISSOR_TEST);
+
+          if (gotAnyRecommendedViewportScale &&
+              gotReducedRecommendedViewportScale &&
+              gotIncreasedRecommendedViewportScale) {
+            done();
+          }
+        };
+      }
+    </script>
+  </body>
+</html>
diff --git a/chrome/updater/device_management/dm_message.cc b/chrome/updater/device_management/dm_message.cc
index 38d7f26..f3dd63e 100644
--- a/chrome/updater/device_management/dm_message.cc
+++ b/chrome/updater/device_management/dm_message.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/updater/device_management/dm_message.h"
 
+#include <map>
 #include <memory>
 #include <utility>
 
@@ -16,6 +17,68 @@
 
 constexpr char kGoogleUpdatePolicyType[] = "google/machine-level-omaha";
 
+namespace {
+enterprise_management::PolicyValidationReportRequest::ValidationResultType
+TranslatePolicyValidationResult(PolicyValidationResult::Status status) {
+  using Report = enterprise_management::PolicyValidationReportRequest;
+  static const std::map<PolicyValidationResult::Status,
+                        Report::ValidationResultType>
+      kValidationStatusMap = {
+          {PolicyValidationResult::Status::kValidationOK,
+           Report::VALIDATION_RESULT_TYPE_SUCCESS},
+          {PolicyValidationResult::Status::kValidationBadInitialSignature,
+           Report::VALIDATION_RESULT_TYPE_BAD_INITIAL_SIGNATURE},
+          {PolicyValidationResult::Status::kValidationBadSignature,
+           Report::VALIDATION_RESULT_TYPE_BAD_SIGNATURE},
+          {PolicyValidationResult::Status::kValidationErrorCodePresent,
+           Report::VALIDATION_RESULT_TYPE_ERROR_CODE_PRESENT},
+          {PolicyValidationResult::Status::kValidationPayloadParseError,
+           Report::VALIDATION_RESULT_TYPE_PAYLOAD_PARSE_ERROR},
+          {PolicyValidationResult::Status::kValidationWrongPolicyType,
+           Report::VALIDATION_RESULT_TYPE_WRONG_POLICY_TYPE},
+          {PolicyValidationResult::Status::kValidationWrongSettingsEntityID,
+           Report::VALIDATION_RESULT_TYPE_WRONG_SETTINGS_ENTITY_ID},
+          {PolicyValidationResult::Status::kValidationBadTimestamp,
+           Report::VALIDATION_RESULT_TYPE_BAD_TIMESTAMP},
+          {PolicyValidationResult::Status::kValidationBadDMToken,
+           Report::VALIDATION_RESULT_TYPE_BAD_DM_TOKEN},
+          {PolicyValidationResult::Status::kValidationBadDeviceID,
+           Report::VALIDATION_RESULT_TYPE_BAD_DEVICE_ID},
+          {PolicyValidationResult::Status::kValidationBadUser,
+           Report::VALIDATION_RESULT_TYPE_BAD_USER},
+          {PolicyValidationResult::Status::kValidationPolicyParseError,
+           Report::VALIDATION_RESULT_TYPE_POLICY_PARSE_ERROR},
+          {PolicyValidationResult::Status::
+               kValidationBadKeyVerificationSignature,
+           Report::VALIDATION_RESULT_TYPE_BAD_KEY_VERIFICATION_SIGNATURE},
+          {PolicyValidationResult::Status::kValidationValueWarning,
+           Report::VALIDATION_RESULT_TYPE_VALUE_WARNING},
+          {PolicyValidationResult::Status::kValidationValueError,
+           Report::VALIDATION_RESULT_TYPE_VALUE_ERROR},
+      };
+
+  auto mapped_status = kValidationStatusMap.find(status);
+  return mapped_status == kValidationStatusMap.end()
+             ? Report::VALIDATION_RESULT_TYPE_ERROR_UNSPECIFIED
+             : mapped_status->second;
+}
+
+enterprise_management::PolicyValueValidationIssue::ValueValidationIssueSeverity
+TranslatePolicyValidationResultSeverity(
+    PolicyValueValidationIssue::Severity severity) {
+  using Issue = enterprise_management::PolicyValueValidationIssue;
+  switch (severity) {
+    case PolicyValueValidationIssue::Severity::kWarning:
+      return Issue::VALUE_VALIDATION_ISSUE_SEVERITY_WARNING;
+    case PolicyValueValidationIssue::Severity::kError:
+      return Issue::VALUE_VALIDATION_ISSUE_SEVERITY_ERROR;
+    default:
+      return Issue::VALUE_VALIDATION_ISSUE_SEVERITY_UNSPECIFIED;
+  }
+}
+
+}  // namespace
+
 std::string GetRegisterBrowserRequestData(const std::string& machine_name,
                                           const std::string& os_platform,
                                           const std::string& os_version) {
@@ -49,6 +112,56 @@
   return dm_request.SerializeAsString();
 }
 
+std::string GetPolicyValidationReportRequestData(
+    const PolicyValidationResult& validation_result) {
+  PolicyValidationResult::Status aggregated_status = validation_result.status;
+
+  if (aggregated_status == PolicyValidationResult::Status::kValidationOK) {
+    for (const PolicyValueValidationIssue& issue : validation_result.issues) {
+      switch (issue.severity) {
+        case PolicyValueValidationIssue::Severity::kError:
+          aggregated_status =
+              PolicyValidationResult::Status::kValidationValueError;
+          break;
+
+        case PolicyValueValidationIssue::Severity::kWarning:
+          aggregated_status =
+              PolicyValidationResult::Status::kValidationValueWarning;
+          break;
+      }
+    }
+  }
+
+  if (aggregated_status == PolicyValidationResult::Status::kValidationOK) {
+    return std::string();
+  }
+
+  enterprise_management::DeviceManagementRequest dm_request;
+
+  enterprise_management::PolicyValidationReportRequest*
+      policy_validation_report_request =
+          dm_request.mutable_policy_validation_report_request();
+  policy_validation_report_request->set_validation_result_type(
+      TranslatePolicyValidationResult(aggregated_status));
+  policy_validation_report_request->set_policy_type(
+      validation_result.policy_type);
+  policy_validation_report_request->set_policy_token(
+      validation_result.policy_token);
+
+  for (const PolicyValueValidationIssue& issue : validation_result.issues) {
+    enterprise_management::PolicyValueValidationIssue*
+        policy_value_validation_issue =
+            policy_validation_report_request
+                ->add_policy_value_validation_issues();
+    policy_value_validation_issue->set_policy_name(issue.policy_name);
+    policy_value_validation_issue->set_severity(
+        TranslatePolicyValidationResultSeverity(issue.severity));
+    policy_value_validation_issue->set_debug_message(issue.message);
+  }
+
+  return dm_request.SerializeAsString();
+}
+
 std::string ParseDeviceRegistrationResponse(const std::string& response_data) {
   enterprise_management::DeviceManagementResponse dm_response;
   if (!dm_response.ParseFromString(response_data) ||
diff --git a/chrome/updater/device_management/dm_message.h b/chrome/updater/device_management/dm_message.h
index 154b22d7..48edf7e7 100644
--- a/chrome/updater/device_management/dm_message.h
+++ b/chrome/updater/device_management/dm_message.h
@@ -32,6 +32,11 @@
 std::string GetPolicyFetchRequestData(const std::string& policy_type,
                                       const CachedPolicyInfo& policy_info);
 
+// Returns the serialized data from a DeviceManagementRequest, which wraps
+// a PolicyValidationReportRequest, to report possible policy validation errors.
+std::string GetPolicyValidationReportRequestData(
+    const PolicyValidationResult& validation_result);
+
 // Parses the DeviceManagementResponse for a device registration request, and
 // returns the DM token. Returns empty string if parsing failed or the response
 // is unexpected.
diff --git a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
index a099473..bebaeba 100644
--- a/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
+++ b/chromecast/browser/accessibility/flutter/flutter_semantics_node_wrapper.cc
@@ -10,7 +10,7 @@
 #include "chromecast/browser/cast_web_contents.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 
 using gallium::castos::ActionProperties;
 using gallium::castos::BooleanProperties;
diff --git a/chromecast/browser/extensions/cast_extension_system.cc b/chromecast/browser/extensions/cast_extension_system.cc
index b0682c4..1f2b439 100644
--- a/chromecast/browser/extensions/cast_extension_system.cc
+++ b/chromecast/browser/extensions/cast_extension_system.cc
@@ -88,8 +88,8 @@
   }
 
   scoped_refptr<extensions::Extension> extension(extensions::Extension::Create(
-      base::FilePath(), extensions::Manifest::COMMAND_LINE, *manifest, 0,
-      std::string(), &error));
+      base::FilePath(), extensions::mojom::ManifestLocation::kCommandLine,
+      *manifest, 0, std::string(), &error));
   if (!extension.get()) {
     LOG(ERROR) << "Failed to create extension: " << error;
     return nullptr;
diff --git a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
index 061b6b00..71fba6b 100644
--- a/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chromecast/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -15,10 +15,10 @@
 #include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
 #include "ui/accessibility/aura/aura_window_properties.h"
 #include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_event.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index c783fe1..540f533 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -155,9 +155,11 @@
 }
 
 # All locales supported by Cast builds. This provides a single point of
-# reference for all GN files referencing a locales list. |locales| is declared
-# in //build/config/locales.gni.
-cast_locales = locales
+# reference for all GN files referencing a locales list.
+# |locales_without_pseudolocales| is declared in //build/config/locales.gni.
+# See https://chromium-review.googlesource.com/488166/ for why we can't use
+# pseudolocales in chromecast.
+cast_locales = locales_without_pseudolocales
 
 # Android currently supports more locales than Desktop and ChromeOS.
 # If Cast will also the android files update this and the Cast grd files.
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index b27da06..72e9a34 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-13856.0.0
\ No newline at end of file
+13857.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 0c26a3074..cc8afb75 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -1396,6 +1396,11 @@
       <message name="IDS_NETWORK_DIAGNOSTICS_VIDEO_CONFERENCING_PROBLEM_MEDIA_FAILURE" desc="Error message shown when a connection cannot be established to the video conferencing media servers">
         Unable to connect to media servers
       </message>
+
+      <!-- Personalization App -->
+      <message name="IDS_PERSONALIZATION_APP_TITLE" desc="Name of the system web app for personalizing ChromeOS.">
+        Wallpaper
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_TITLE.png.sha1 b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_TITLE.png.sha1
new file mode 100644
index 0000000..0d23199
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_PERSONALIZATION_APP_TITLE.png.sha1
@@ -0,0 +1 @@
+4a629e521b00d56d08511bad0a29d723dc4ccfa0
\ No newline at end of file
diff --git a/chromeos/components/BUILD.gn b/chromeos/components/BUILD.gn
index 82cc1d501..2703981a 100644
--- a/chromeos/components/BUILD.gn
+++ b/chromeos/components/BUILD.gn
@@ -63,6 +63,7 @@
     "//chromeos/components/help_app_ui:closure_compile",
     "//chromeos/components/media_app_ui:closure_compile",
     "//chromeos/components/multidevice/debug_webui/resources:closure_compile",
+    "//chromeos/components/personalization_app:closure_compile",
     "//chromeos/components/print_management:closure_compile",
     "//chromeos/components/scanning:closure_compile",
     "//chromeos/components/system_apps:closure_compile",
diff --git a/chromeos/components/personalization_app/BUILD.gn b/chromeos/components/personalization_app/BUILD.gn
new file mode 100644
index 0000000..7d68cda
--- /dev/null
+++ b/chromeos/components/personalization_app/BUILD.gn
@@ -0,0 +1,25 @@
+# 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.
+
+assert(is_chromeos, "Personalization App is Chrome OS only")
+
+static_library("personalization_app") {
+  sources = [
+    "personalization_app_ui.cc",
+    "personalization_app_ui.h",
+    "personalization_app_url_constants.cc",
+    "personalization_app_url_constants.h",
+  ]
+
+  deps = [
+    "//chromeos/resources:personalization_app_resources",
+    "//chromeos/strings",
+    "//content/public/browser",
+    "//ui/webui",
+  ]
+}
+
+group("closure_compile") {
+  deps = [ "resources:closure_compile" ]
+}
diff --git a/chromeos/components/personalization_app/DEPS b/chromeos/components/personalization_app/DEPS
new file mode 100644
index 0000000..0d2a509f4
--- /dev/null
+++ b/chromeos/components/personalization_app/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "-chrome",
+  "+chromeos/grit/chromeos_personalization_app_resources.h",
+  "+content/public/browser",
+  "+ui/webui",
+]
diff --git a/chromeos/components/personalization_app/OWNERS b/chromeos/components/personalization_app/OWNERS
new file mode 100644
index 0000000..dd0c97af
--- /dev/null
+++ b/chromeos/components/personalization_app/OWNERS
@@ -0,0 +1 @@
+file://chromeos/assistant/OWNERS
diff --git a/chromeos/components/personalization_app/personalization_app_ui.cc b/chromeos/components/personalization_app/personalization_app_ui.cc
new file mode 100644
index 0000000..ef97f6c
--- /dev/null
+++ b/chromeos/components/personalization_app/personalization_app_ui.cc
@@ -0,0 +1,53 @@
+// 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 "chromeos/components/personalization_app/personalization_app_ui.h"
+
+#include "chromeos/components/personalization_app/personalization_app_url_constants.h"
+#include "chromeos/grit/chromeos_personalization_app_resources.h"
+#include "chromeos/grit/chromeos_personalization_app_resources_map.h"
+#include "chromeos/strings/grit/chromeos_strings.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_ui_data_source.h"
+#include "ui/webui/mojo_web_ui_controller.h"
+
+namespace chromeos {
+
+namespace {
+
+void AddResources(content::WebUIDataSource* source) {
+  source->AddResourcePath("", IDR_CHROMEOS_PERSONALIZATION_APP_INDEX_HTML);
+  source->AddResourcePaths(
+      base::make_span(kChromeosPersonalizationAppResources,
+                      kChromeosPersonalizationAppResourcesSize));
+
+#if !DCHECK_IS_ON()
+  source->SetDefaultResource(IDR_CHROMEOS_PERSONALIZATION_APP_INDEX_HTML);
+#endif  // !DCHECK_IS_ON()
+}
+
+void AddStrings(content::WebUIDataSource* source) {
+  static constexpr webui::LocalizedString kLocalizedStrings[] = {
+      {"title", IDS_PERSONALIZATION_APP_TITLE}};
+  source->AddLocalizedStrings(kLocalizedStrings);
+  source->UseStringsJs();
+}
+
+}  // namespace
+
+PersonalizationAppUI::PersonalizationAppUI(content::WebUI* web_ui)
+    : ui::MojoWebUIController(web_ui) {
+  auto source = base::WrapUnique(
+      content::WebUIDataSource::Create(kChromeUIPersonalizationAppHost));
+
+  AddResources(source.get());
+  AddStrings(source.get());
+
+  auto* browser_context = web_ui->GetWebContents()->GetBrowserContext();
+  content::WebUIDataSource::Add(browser_context, source.release());
+}
+
+PersonalizationAppUI::~PersonalizationAppUI() = default;
+
+}  // namespace chromeos
diff --git a/chromeos/components/personalization_app/personalization_app_ui.h b/chromeos/components/personalization_app/personalization_app_ui.h
new file mode 100644
index 0000000..765a786
--- /dev/null
+++ b/chromeos/components/personalization_app/personalization_app_ui.h
@@ -0,0 +1,22 @@
+// 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 CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_UI_H_
+#define CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_UI_H_
+
+#include "ui/webui/mojo_web_ui_controller.h"
+
+namespace chromeos {
+
+class PersonalizationAppUI : public ui::MojoWebUIController {
+ public:
+  explicit PersonalizationAppUI(content::WebUI* web_ui);
+  PersonalizationAppUI(const PersonalizationAppUI&) = delete;
+  PersonalizationAppUI& operator=(const PersonalizationAppUI&) = delete;
+  ~PersonalizationAppUI() override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_UI_H_
diff --git a/chromeos/components/personalization_app/personalization_app_url_constants.cc b/chromeos/components/personalization_app/personalization_app_url_constants.cc
new file mode 100644
index 0000000..4cf78de
--- /dev/null
+++ b/chromeos/components/personalization_app/personalization_app_url_constants.cc
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/personalization_app/personalization_app_url_constants.h"
+
+namespace chromeos {
+
+const char kChromeUIPersonalizationAppHost[] = "personalization";
+const char kChromeUIPersonalizationAppURL[] = "chrome://personalization";
+
+}  // namespace chromeos
diff --git a/chromeos/components/personalization_app/personalization_app_url_constants.h b/chromeos/components/personalization_app/personalization_app_url_constants.h
new file mode 100644
index 0000000..36642e86
--- /dev/null
+++ b/chromeos/components/personalization_app/personalization_app_url_constants.h
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_URL_CONSTANTS_H_
+#define CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_URL_CONSTANTS_H_
+
+namespace chromeos {
+
+extern const char kChromeUIPersonalizationAppHost[];
+extern const char kChromeUIPersonalizationAppURL[];
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PERSONALIZATION_APP_PERSONALIZATION_APP_URL_CONSTANTS_H_
diff --git a/chromeos/components/personalization_app/resources/BUILD.gn b/chromeos/components/personalization_app/resources/BUILD.gn
new file mode 100644
index 0000000..583104a
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/BUILD.gn
@@ -0,0 +1,27 @@
+# Copyright 2021 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/grit/grit_rule.gni")
+import("//ui/webui/resources/tools/generate_grd.gni")
+
+generate_grd("build_grd") {
+  input_files_base_dir = rebase_path(".", "//")
+  input_files = [
+    "index.html",
+    "icon_192.png",
+    "personalization_app.js",
+  ]
+  manifest_files = []
+  grd_prefix = "chromeos_personalization_app"
+  out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
+}
+
+js_type_check("closure_compile") {
+  is_polymer3 = true
+  deps = [ ":personalization_app" ]
+}
+
+js_library("personalization_app") {
+}
diff --git a/chromeos/components/personalization_app/resources/icon_192.png b/chromeos/components/personalization_app/resources/icon_192.png
new file mode 100644
index 0000000..86cc40b1
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/icon_192.png
Binary files differ
diff --git a/chromeos/components/personalization_app/resources/index.html b/chromeos/components/personalization_app/resources/index.html
new file mode 100644
index 0000000..380bdd2
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/index.html
@@ -0,0 +1,14 @@
+<!-- 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. -->
+<!DOCTYPE html>
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
+  <head>
+    <title>$i18n{title}</title>
+    <link rel="icon" type="image/png" sizes="192x192" href="icon_192.png">
+    <meta charset="utf-8">
+    <script type="module" src="personalization_app.js" defer></script>
+  </head>
+  <body>
+  </body>
+</html>
diff --git a/chromeos/components/personalization_app/resources/personalization_app.js b/chromeos/components/personalization_app/resources/personalization_app.js
new file mode 100644
index 0000000..8e23dc9
--- /dev/null
+++ b/chromeos/components/personalization_app/resources/personalization_app.js
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview the main entry point for the Wallpaper app.
+ */
+
+import '/strings.m.js';
+
+// TODO(b/182012641) move wallpaper functionality here from chrome://os-settings
+function testing() {
+  console.log('Personalization App Loaded');
+}
+
+document.addEventListener('DOMContentLoaded', testing);
diff --git a/chromeos/network/cellular_inhibitor.cc b/chromeos/network/cellular_inhibitor.cc
index b07a2bd..f53fd1e7 100644
--- a/chromeos/network/cellular_inhibitor.cc
+++ b/chromeos/network/cellular_inhibitor.cc
@@ -117,7 +117,7 @@
     DCHECK(!GetInhibitReason());
     NET_LOG(EVENT) << ss.str();
   } else {
-    NET_LOG(EVENT) << ss.str() << state_ << ", reason: " << *GetInhibitReason();
+    NET_LOG(EVENT) << ss.str() << ", reason: " << *GetInhibitReason();
   }
 
   if (was_inhibited != is_inhibited)
diff --git a/chromeos/resources/BUILD.gn b/chromeos/resources/BUILD.gn
index e3d5edc..4005a596 100644
--- a/chromeos/resources/BUILD.gn
+++ b/chromeos/resources/BUILD.gn
@@ -314,3 +314,22 @@
   ]
   output_dir = "$root_gen_dir/chromeos"
 }
+
+# Resources used by chrome://personalization SWA.
+grit("personalization_app_resources") {
+  # These arguments are needed since the grd is generated at build time.
+  enable_input_discovery_for_gn_analyze = false
+  personalization_app_gen_dir =
+      "$root_gen_dir/chromeos/components/personalization_app/resources"
+  source =
+      "$personalization_app_gen_dir/chromeos_personalization_app_resources.grd"
+  deps = [ "//chromeos/components/personalization_app/resources:build_grd" ]
+
+  outputs = [
+    "grit/chromeos_personalization_app_resources.h",
+    "grit/chromeos_personalization_app_resources_map.cc",
+    "grit/chromeos_personalization_app_resources_map.h",
+    "chromeos_personalization_app_resources.pak",
+  ]
+  output_dir = "$root_gen_dir/chromeos"
+}
diff --git a/chromeos/services/network_config/cros_network_config.cc b/chromeos/services/network_config/cros_network_config.cc
index 38d6b2097..19f86b2 100644
--- a/chromeos/services/network_config/cros_network_config.cc
+++ b/chromeos/services/network_config/cros_network_config.cc
@@ -488,8 +488,32 @@
   return sim_info_mojos;
 }
 
+mojom::InhibitReason GetInhibitReason(CellularInhibitor* cellular_inhibitor) {
+  if (!cellular_inhibitor)
+    return mojom::InhibitReason::kNotInhibited;
+
+  base::Optional<CellularInhibitor::InhibitReason> inhibit_reason =
+      cellular_inhibitor->GetInhibitReason();
+  if (!inhibit_reason)
+    return mojom::InhibitReason::kNotInhibited;
+
+  switch (*inhibit_reason) {
+    case CellularInhibitor::InhibitReason::kInstallingProfile:
+      return mojom::InhibitReason::kInstallingProfile;
+    case CellularInhibitor::InhibitReason::kRenamingProfile:
+      return mojom::InhibitReason::kRenamingProfile;
+    case CellularInhibitor::InhibitReason::kRemovingProfile:
+      return mojom::InhibitReason::kRemovingProfile;
+    case CellularInhibitor::InhibitReason::kConnectingToProfile:
+      return mojom::InhibitReason::kConnectingToProfile;
+    case CellularInhibitor::InhibitReason::kRefreshingProfileList:
+      return mojom::InhibitReason::kRefreshingProfileList;
+  }
+}
+
 mojom::DeviceStatePropertiesPtr DeviceStateToMojo(
     const DeviceState* device,
+    CellularInhibitor* cellular_inhibitor,
     mojom::DeviceStateType technology_state) {
   mojom::NetworkType type = ShillTypeToMojo(device->type());
   if (type == mojom::NetworkType::kAll) {
@@ -534,6 +558,7 @@
   }
   if (type == mojom::NetworkType::kCellular) {
     result->sim_infos = CellularSIMInfosToMojo(device);
+    result->inhibit_reason = GetInhibitReason(cellular_inhibitor);
   }
   return result;
 }
@@ -1843,6 +1868,7 @@
     : CrosNetworkConfig(
           NetworkHandler::Get()->network_state_handler(),
           NetworkHandler::Get()->network_device_handler(),
+          NetworkHandler::Get()->cellular_inhibitor(),
           NetworkHandler::Get()->cellular_esim_profile_handler(),
           NetworkHandler::Get()->managed_network_configuration_handler(),
           NetworkHandler::Get()->network_connection_handler(),
@@ -1851,12 +1877,14 @@
 CrosNetworkConfig::CrosNetworkConfig(
     NetworkStateHandler* network_state_handler,
     NetworkDeviceHandler* network_device_handler,
+    CellularInhibitor* cellular_inhibitor,
     CellularESimProfileHandler* cellular_esim_profile_handler,
     ManagedNetworkConfigurationHandler* network_configuration_handler,
     NetworkConnectionHandler* network_connection_handler,
     NetworkCertificateHandler* network_certificate_handler)
     : network_state_handler_(network_state_handler),
       network_device_handler_(network_device_handler),
+      cellular_inhibitor_(cellular_inhibitor),
       cellular_esim_profile_handler_(cellular_esim_profile_handler),
       network_configuration_handler_(network_configuration_handler),
       network_connection_handler_(network_connection_handler),
@@ -1871,6 +1899,8 @@
       network_certificate_handler_->HasObserver(this)) {
     network_certificate_handler_->RemoveObserver(this);
   }
+  if (cellular_inhibitor_ && cellular_inhibitor_->HasObserver(this))
+    cellular_inhibitor_->RemoveObserver(this);
 }
 
 void CrosNetworkConfig::BindReceiver(
@@ -1887,6 +1917,8 @@
       !network_certificate_handler_->HasObserver(this)) {
     network_certificate_handler_->AddObserver(this);
   }
+  if (cellular_inhibitor_ && !cellular_inhibitor_->HasObserver(this))
+    cellular_inhibitor_->AddObserver(this);
   observers_.Add(std::move(observer));
 }
 
@@ -1966,12 +1998,14 @@
       NET_LOG(ERROR) << "Device state unavailable: " << device->name();
       continue;
     }
-    if (technology_state == mojom::DeviceStateType::kEnabled &&
-        device->inhibited()) {
+    if (device->type() == shill::kTypeCellular &&
+        technology_state == mojom::DeviceStateType::kEnabled &&
+        cellular_inhibitor_ &&
+        cellular_inhibitor_->GetInhibitReason().has_value()) {
       technology_state = mojom::DeviceStateType::kInhibited;
     }
     mojom::DeviceStatePropertiesPtr mojo_device =
-        DeviceStateToMojo(device, technology_state);
+        DeviceStateToMojo(device, cellular_inhibitor_, technology_state);
     if (mojo_device)
       result.emplace_back(std::move(mojo_device));
   }
@@ -2786,6 +2820,10 @@
     observer->OnNetworkCertificatesChanged();
 }
 
+void CrosNetworkConfig::OnInhibitStateChanged() {
+  DeviceListChanged();
+}
+
 const std::string& CrosNetworkConfig::GetServicePathFromGuid(
     const std::string& guid) {
   const chromeos::NetworkState* network =
diff --git a/chromeos/services/network_config/cros_network_config.h b/chromeos/services/network_config/cros_network_config.h
index a6b3a74..10a68d6 100644
--- a/chromeos/services/network_config/cros_network_config.h
+++ b/chromeos/services/network_config/cros_network_config.h
@@ -7,6 +7,7 @@
 
 #include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
+#include "chromeos/network/cellular_inhibitor.h"
 #include "chromeos/network/network_certificate_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
@@ -17,7 +18,7 @@
 
 namespace base {
 class DictionaryValue;
-}
+}  // namespace base
 
 namespace chromeos {
 
@@ -31,7 +32,8 @@
 
 class CrosNetworkConfig : public mojom::CrosNetworkConfig,
                           public NetworkStateHandlerObserver,
-                          public NetworkCertificateHandler::Observer {
+                          public NetworkCertificateHandler::Observer,
+                          public CellularInhibitor::Observer {
  public:
   // Constructs an instance of CrosNetworkConfig with default network subsystem
   // dependencies appropriate for a production environment.
@@ -42,6 +44,7 @@
   CrosNetworkConfig(
       NetworkStateHandler* network_state_handler,
       NetworkDeviceHandler* network_device_handler,
+      CellularInhibitor* cellular_inhibitor,
       CellularESimProfileHandler* cellular_esim_profile_handler,
       ManagedNetworkConfigurationHandler* network_configuration_handler,
       NetworkConnectionHandler* network_connection_handler,
@@ -144,7 +147,7 @@
       const std::string& error_name,
       std::unique_ptr<base::DictionaryValue> error_data);
 
-  // NetworkStateHandlerObserver
+  // NetworkStateHandlerObserver:
   void NetworkListChanged() override;
   void DeviceListChanged() override;
   void ActiveNetworksChanged(
@@ -158,10 +161,14 @@
   // NetworkCertificateHandler::Observer
   void OnCertificatesChanged() override;
 
+  // CellularInhibitor::Observer:
+  void OnInhibitStateChanged() override;
+
   const std::string& GetServicePathFromGuid(const std::string& guid);
 
   NetworkStateHandler* network_state_handler_;    // Unowned
   NetworkDeviceHandler* network_device_handler_;  // Unowned
+  CellularInhibitor* cellular_inhibitor_;         // Unowned
   CellularESimProfileHandler* cellular_esim_profile_handler_;  // Unowned
   ManagedNetworkConfigurationHandler*
       network_configuration_handler_;                       // Unowned
diff --git a/chromeos/services/network_config/cros_network_config_unittest.cc b/chromeos/services/network_config/cros_network_config_unittest.cc
index 47008b9..78a5c72 100644
--- a/chromeos/services/network_config/cros_network_config_unittest.cc
+++ b/chromeos/services/network_config/cros_network_config_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "chromeos/dbus/shill/fake_shill_device_client.h"
 #include "chromeos/login/login_state/login_state.h"
@@ -29,6 +30,7 @@
 #include "chromeos/network/proxy/ui_proxy_config_service.h"
 #include "chromeos/network/system_token_cert_db_storage.h"
 #include "chromeos/network/test_cellular_esim_profile_handler.h"
+#include "chromeos/network/test_cellular_inhibitor.h"
 #include "chromeos/services/network_config/public/cpp/cros_network_config_test_observer.h"
 #include "chromeos/services/network_config/public/mojom/cros_network_config.mojom-shared.h"
 #include "components/onc/onc_constants.h"
@@ -101,6 +103,9 @@
             helper_.network_state_handler(), network_profile_handler_.get(),
             network_device_handler_.get(), network_configuration_handler_.get(),
             ui_proxy_config_service_.get());
+    cellular_inhibitor_ = std::make_unique<TestCellularInhibitor>();
+    cellular_inhibitor_->Init(helper_.network_state_handler(),
+                              network_device_handler_.get());
     cellular_esim_profile_handler_ =
         std::make_unique<TestCellularESimProfileHandler>();
     cellular_esim_profile_handler_->Init();
@@ -114,7 +119,7 @@
         std::make_unique<NetworkCertificateHandler>();
     cros_network_config_ = std::make_unique<CrosNetworkConfig>(
         helper_.network_state_handler(), network_device_handler_.get(),
-        cellular_esim_profile_handler_.get(),
+        cellular_inhibitor_.get(), cellular_esim_profile_handler_.get(),
         managed_network_configuration_handler_.get(),
         network_connection_handler_.get(), network_certificate_handler_.get());
     SetupPolicy();
@@ -525,6 +530,23 @@
     return false;
   }
 
+  std::unique_ptr<CellularInhibitor::InhibitLock> InhibitCellularScanning(
+      CellularInhibitor::InhibitReason inhibit_reason) {
+    base::RunLoop run_loop;
+
+    std::unique_ptr<CellularInhibitor::InhibitLock> inhibit_lock;
+    cellular_inhibitor_->InhibitCellularScanning(
+        inhibit_reason,
+        base::BindLambdaForTesting(
+            [&](std::unique_ptr<CellularInhibitor::InhibitLock> result) {
+              inhibit_lock = std::move(result);
+              run_loop.Quit();
+            }));
+
+    run_loop.Run();
+    return inhibit_lock;
+  }
+
   NetworkStateTestHelper& helper() { return helper_; }
   CrosNetworkConfigTestObserver* observer() { return observer_.get(); }
   CrosNetworkConfig* cros_network_config() {
@@ -550,6 +572,7 @@
   std::unique_ptr<NetworkConfigurationHandler> network_configuration_handler_;
   std::unique_ptr<ManagedNetworkConfigurationHandler>
       managed_network_configuration_handler_;
+  std::unique_ptr<TestCellularInhibitor> cellular_inhibitor_;
   std::unique_ptr<TestCellularESimProfileHandler>
       cellular_esim_profile_handler_;
   std::unique_ptr<NetworkConnectionHandler> network_connection_handler_;
@@ -1234,6 +1257,22 @@
   EXPECT_EQ(mojom::DeviceStateType::kDisabled, devices[0]->device_state);
 }
 
+TEST_F(CrosNetworkConfigTest, CellularInhibitState) {
+  mojom::DeviceStatePropertiesPtr cellular =
+      GetDeviceStateFromList(mojom::NetworkType::kCellular);
+  ASSERT_TRUE(cellular);
+  EXPECT_EQ(mojom::DeviceStateType::kEnabled, cellular->device_state);
+  EXPECT_EQ(mojom::InhibitReason::kNotInhibited, cellular->inhibit_reason);
+
+  std::unique_ptr<CellularInhibitor::InhibitLock> lock =
+      InhibitCellularScanning(
+          CellularInhibitor::InhibitReason::kInstallingProfile);
+  cellular = GetDeviceStateFromList(mojom::NetworkType::kCellular);
+  ASSERT_TRUE(cellular);
+  EXPECT_EQ(mojom::DeviceStateType::kInhibited, cellular->device_state);
+  EXPECT_EQ(mojom::InhibitReason::kInstallingProfile, cellular->inhibit_reason);
+}
+
 TEST_F(CrosNetworkConfigTest, SetCellularSimState) {
   // Assert initial state.
   mojom::DeviceStatePropertiesPtr cellular =
diff --git a/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc b/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc
index 8b0102ca..8a02619e 100644
--- a/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc
+++ b/chromeos/services/network_config/public/cpp/cros_network_config_test_helper.cc
@@ -32,6 +32,7 @@
     cros_network_config_impl_ = std::make_unique<CrosNetworkConfig>(
         network_state_helper_.network_state_handler(),
         network_state_helper_.network_device_handler(),
+        /*cellular_inhibitor=*/nullptr,
         /*cellular_esim_profile_handler=*/nullptr,
         network_configuration_handler,
         /*network_connection_handler=*/nullptr,
diff --git a/chromeos/services/network_config/public/mojom/cros_network_config.mojom b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
index b472338..c6b5230 100644
--- a/chromeos/services/network_config/public/mojom/cros_network_config.mojom
+++ b/chromeos/services/network_config/public/mojom/cros_network_config.mojom
@@ -116,6 +116,25 @@
   kUserCert,
 };
 
+// Reasons why the Cellular Device may have its scanning inhibited (i.e.,
+// temporarily stopped).
+enum InhibitReason {
+  // Not inhibited.
+  kNotInhibited,
+  // Inhibited because an eSIM profile is being installed.
+  kInstallingProfile,
+  // Inhibited because an eSIM profile is being renamed.
+  kRenamingProfile,
+  // Inhibited because an eSIM profile is being removed.
+  kRemovingProfile,
+  // Inhibited because a connection is in progress which requires that the
+  // device switch to a different eSIM profile.
+  kConnectingToProfile,
+  // Inhibited because the list of pending eSIM profiles is being refreshed by
+  // checking with an SMDS server.
+  kRefreshingProfileList
+};
+
 // The SIM card lock status for Cellular networks.
 struct SIMLockStatus {
   // The status of SIM lock. Possible values are 'sim-pin', 'sim-puk' or empty.
@@ -253,6 +272,8 @@
   // Details about the physical SIM and eSIM available on the device if Type =
   // Cellular. Note that the array will be ordered by the |slot_id|.
   array<SIMInfo>? sim_infos;
+  // The reason for cellular scans to be inhibited; only set if Type = Cellular.
+  InhibitReason inhibit_reason = kNotInhibited;
   // True when a SIM is required and not present.
   bool sim_absent = false;
   DeviceStateType device_state;
diff --git a/components/assist_ranker/base_predictor.cc b/components/assist_ranker/base_predictor.cc
index 8fd8fbf5f..c5d774e 100644
--- a/components/assist_ranker/base_predictor.cc
+++ b/components/assist_ranker/base_predictor.cc
@@ -58,8 +58,8 @@
                                     ukm::UkmEntryBuilder* ukm_builder) {
   DCHECK(ukm_builder);
 
-  if (!base::Contains(*config_.feature_whitelist, feature_name)) {
-    DVLOG(1) << "Feature not whitelisted: " << feature_name;
+  if (!base::Contains(*config_.feature_allowlist, feature_name)) {
+    DVLOG(1) << "Feature not allowed: " << feature_name;
     return;
   }
 
@@ -95,12 +95,12 @@
     return;
   }
 
-  if (!config_.feature_whitelist) {
-    DVLOG(0) << "No whitelist specified.";
+  if (!config_.feature_allowlist) {
+    DVLOG(0) << "No allowlist specified.";
     return;
   }
-  if (config_.feature_whitelist->empty()) {
-    DVLOG(0) << "Empty whitelist, examples will not be logged.";
+  if (config_.feature_allowlist->empty()) {
+    DVLOG(0) << "Empty allowlist, examples will not be logged.";
     return;
   }
 
diff --git a/components/assist_ranker/base_predictor_unittest.cc b/components/assist_ranker/base_predictor_unittest.cc
index de929a9..5ca2d598 100644
--- a/components/assist_ranker/base_predictor_unittest.cc
+++ b/components/assist_ranker/base_predictor_unittest.cc
@@ -32,18 +32,18 @@
 const char kTestUrlParamName[] = "ranker-model-url";
 const char kTestDefaultModelUrl[] = "https://foo.bar/model.bin";
 
-// The whitelisted features must be metrics of kTestLoggingName in ukm.xml,
+// The allowed features must be metrics of kTestLoggingName in ukm.xml,
 // though the types do not need to match.
 const char kBoolFeature[] = "DidOptIn";
 const char kIntFeature[] = "DurationAfterScrollMs";
 const char kFloatFeature[] = "FontSize";
 const char kStringFeature[] = "IsEntity";
 const char kStringListFeature[] = "IsEntityEligible";
-const char kFeatureNotWhitelisted[] = "not_whitelisted";
+const char kFeatureNotAllowed[] = "not_allowed";
 
 const char kTestNavigationUrl[] = "https://foo.com";
 
-const base::flat_set<std::string> kFeatureWhitelist({kBoolFeature, kIntFeature,
+const base::flat_set<std::string> kFeatureAllowlist({kBoolFeature, kIntFeature,
                                                      kFloatFeature,
                                                      kStringFeature,
                                                      kStringListFeature});
@@ -57,7 +57,7 @@
 const PredictorConfig kTestPredictorConfig =
     PredictorConfig{kTestModelName,     kTestLoggingName,
                     kTestUmaPrefixName, LOG_UKM,
-                    &kFeatureWhitelist, &kTestRankerQuery,
+                    &kFeatureAllowlist, &kTestRankerQuery,
                     &kTestRankerUrl,    kNoPredictThresholdReplacement};
 
 // Class that implements virtual functions of the base class.
@@ -164,7 +164,7 @@
   features[kStringListFeature].mutable_string_list()->add_string_value("42");
 
   // This feature will not be logged.
-  features[kFeatureNotWhitelisted].set_bool_value(false);
+  features[kFeatureNotAllowed].set_bool_value(false);
 
   predictor->LogExampleToUkm(example, GetSourceId());
 
@@ -185,14 +185,14 @@
                                           360287971246764839);
 
   EXPECT_FALSE(
-      GetTestUkmRecorder()->EntryHasMetric(entries[0], kFeatureNotWhitelisted));
+      GetTestUkmRecorder()->EntryHasMetric(entries[0], kFeatureNotAllowed));
 }
 
 TEST_F(BasePredictorTest, GetPredictThresholdReplacement) {
   float altered_threshold = 0.78f;  // Arbitrary value.
   const PredictorConfig altered_threshold_config{
       kTestModelName,  kTestLoggingName,   kTestUmaPrefixName,
-      LOG_UKM,         &kFeatureWhitelist, &kTestRankerQuery,
+      LOG_UKM,         &kFeatureAllowlist, &kTestRankerQuery,
       &kTestRankerUrl, altered_threshold};
   auto predictor = FakePredictor::Create(altered_threshold_config);
   EXPECT_EQ(altered_threshold, predictor->GetPredictThresholdReplacement());
diff --git a/components/assist_ranker/binary_classifier_predictor_unittest.cc b/components/assist_ranker/binary_classifier_predictor_unittest.cc
index fec0fca3..9d66221 100644
--- a/components/assist_ranker/binary_classifier_predictor_unittest.cc
+++ b/components/assist_ranker/binary_classifier_predictor_unittest.cc
@@ -73,7 +73,7 @@
 PredictorConfig BinaryClassifierPredictorTest::GetConfig(
     float predictor_threshold_replacement) {
   PredictorConfig config("model_name", "logging_name", "uma_prefix", LOG_NONE,
-                         GetEmptyWhitelist(), &kTestRankerQuery,
+                         GetEmptyAllowlist(), &kTestRankerQuery,
                          &kTestRankerUrl, predictor_threshold_replacement);
 
   return config;
diff --git a/components/assist_ranker/classifier_predictor_unittest.cc b/components/assist_ranker/classifier_predictor_unittest.cc
index f6c55f7..8718e15 100644
--- a/components/assist_ranker/classifier_predictor_unittest.cc
+++ b/components/assist_ranker/classifier_predictor_unittest.cc
@@ -72,7 +72,7 @@
 
 PredictorConfig ClassifierPredictorTest::GetConfig() {
   return PredictorConfig("model_name", "logging_name", "uma_prefix", LOG_NONE,
-                         GetEmptyWhitelist(), &kTestRankerQuery,
+                         GetEmptyAllowlist(), &kTestRankerQuery,
                          &kTestRankerUrl, 0);
 }
 
diff --git a/components/assist_ranker/predictor_config.cc b/components/assist_ranker/predictor_config.cc
index 57434e5..eb0f340 100644
--- a/components/assist_ranker/predictor_config.cc
+++ b/components/assist_ranker/predictor_config.cc
@@ -6,9 +6,9 @@
 
 namespace assist_ranker {
 
-const base::flat_set<std::string>* GetEmptyWhitelist() {
-  static auto* whitelist = new base::flat_set<std::string>();
-  return whitelist;
+const base::flat_set<std::string>* GetEmptyAllowlist() {
+  static auto* allowlist = new base::flat_set<std::string>();
+  return allowlist;
 }
 
 }  // namespace assist_ranker
diff --git a/components/assist_ranker/predictor_config.h b/components/assist_ranker/predictor_config.h
index 944164b4..5ee3a1d3 100644
--- a/components/assist_ranker/predictor_config.h
+++ b/components/assist_ranker/predictor_config.h
@@ -18,8 +18,8 @@
   LOG_UKM = 1,
 };
 
-// Empty feature whitelist used for testing.
-const base::flat_set<std::string>* GetEmptyWhitelist();
+// Empty feature allowlist used for testing.
+const base::flat_set<std::string>* GetEmptyAllowlist();
 
 // This struct holds the config options for logging, loading and field trial
 // for a predictor.
@@ -28,7 +28,7 @@
                   const char* logging_name,
                   const char* uma_prefix,
                   const LogType log_type,
-                  const base::flat_set<std::string>* feature_whitelist,
+                  const base::flat_set<std::string>* feature_allowlist,
                   const base::Feature* field_trial,
                   const base::FeatureParam<std::string>* field_trial_url_param,
                   float field_trial_threshold_replacement_param)
@@ -36,7 +36,7 @@
         logging_name(logging_name),
         uma_prefix(uma_prefix),
         log_type(log_type),
-        feature_whitelist(feature_whitelist),
+        feature_allowlist(feature_allowlist),
         field_trial(field_trial),
         field_trial_url_param(field_trial_url_param),
         field_trial_threshold_replacement_param(
@@ -45,7 +45,7 @@
   const char* const logging_name;
   const char* const uma_prefix;
   const LogType log_type;
-  const base::flat_set<std::string>* feature_whitelist;
+  const base::flat_set<std::string>* feature_allowlist;
   const base::Feature* field_trial;
   const base::FeatureParam<std::string>* field_trial_url_param;
   const float field_trial_threshold_replacement_param;
diff --git a/components/assist_ranker/predictor_config_definitions.cc b/components/assist_ranker/predictor_config_definitions.cc
index 786d77f..5448f64 100644
--- a/components/assist_ranker/predictor_config_definitions.cc
+++ b/components/assist_ranker/predictor_config_definitions.cc
@@ -40,10 +40,10 @@
 
 // NOTE: This list needs to be kept in sync with tools/metrics/ukm/ukm.xml!
 // Only features within this list will be logged to UKM.
-// TODO(chrome-ranker-team) Deprecate the whitelist once it is available through
+// TODO(chrome-ranker-team) Deprecate the allowlist once it is available through
 // the UKM generated API.
-const base::flat_set<std::string>* GetContextualSearchFeatureWhitelist() {
-  static auto* kContextualSearchFeatureWhitelist =
+const base::flat_set<std::string>* GetContextualSearchFeatureAllowlist() {
+  static auto* kContextualSearchFeatureAllowlist =
       new base::flat_set<std::string>({"DidOptIn",
                                        "DurationAfterScrollMs",
                                        "EntityImpressionsCount",
@@ -78,7 +78,7 @@
                                        "TapCount",
                                        "TapDurationMs",
                                        "WasScreenBottom"});
-  return kContextualSearchFeatureWhitelist;
+  return kContextualSearchFeatureAllowlist;
 }
 
 }  // namespace
@@ -87,7 +87,7 @@
   static auto kContextualSearchPredictorConfig = *(new PredictorConfig(
       kContextualSearchModelName, kContextualSearchLoggingName,
       kContextualSearchUmaPrefixName, LOG_UKM,
-      GetContextualSearchFeatureWhitelist(), &kContextualSearchRankerQuery,
+      GetContextualSearchFeatureAllowlist(), &kContextualSearchRankerQuery,
       GetContextualSearchRankerUrlFeatureParam(),
       GetContextualSearchRankerThresholdFeatureParam()));
   return kContextualSearchPredictorConfig;
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
index 68ba45b1..76c8c734 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SingleCategorySettings.java
@@ -399,18 +399,15 @@
         if (preference instanceof WebsitePreference) {
             WebsitePreference website_pref = (WebsitePreference) preference;
 
-            if (getSiteSettingsDelegate().isPageInfoV2Enabled()
-                    && !website_pref.getParent().getKey().equals(MANAGED_GROUP)) {
-                buildPreferenceDialog(website_pref.site()).show();
-            } else {
+            if (website_pref.getParent().getKey().equals(MANAGED_GROUP)) {
                 website_pref.setFragment(SingleWebsiteSettings.class.getName());
-
                 website_pref.putSiteAddressIntoExtras(SingleWebsiteSettings.EXTRA_SITE_ADDRESS);
-
                 int navigationSource = getArguments().getInt(
                         SettingsNavigationSource.EXTRA_KEY, SettingsNavigationSource.OTHER);
                 website_pref.getExtras().putInt(
                         SettingsNavigationSource.EXTRA_KEY, navigationSource);
+            } else {
+                buildPreferenceDialog(website_pref.site()).show();
             }
         }
 
diff --git a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
index d3ee6e05..cb6442b 100644
--- a/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
+++ b/components/browser_ui/site_settings/android/java/src/org/chromium/components/browser_ui/site_settings/SiteSettingsDelegate.java
@@ -80,11 +80,6 @@
     String getDelegatePackageNameForOrigin(Origin origin, @ContentSettingsType int type);
 
     /**
-     * @return true if PageInfo V2 is enabled.
-     */
-    boolean isPageInfoV2Enabled();
-
-    /**
      * @return true if Help and Feedback links and menu items should be shown to the user.
      */
     boolean isHelpAndFeedbackEnabled();
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index ae39a01..ff4323a 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -1024,7 +1024,7 @@
 gfx::Rect ClientControlledShellSurface::GetShadowBounds() const {
   gfx::Rect shadow_bounds = ShellSurfaceBase::GetShadowBounds();
   const ash::NonClientFrameViewAsh* frame_view = GetFrameView();
-  if (frame_view->GetVisible()) {
+  if (frame_view->GetFrameEnabled()) {
     // The client controlled geometry is only for the client
     // area. When the chrome side frame is enabled, the shadow height
     // has to include the height of the frame, and the total height is
@@ -1083,7 +1083,7 @@
 base::Optional<gfx::Rect> ClientControlledShellSurface::GetWidgetBounds()
     const {
   const ash::NonClientFrameViewAsh* frame_view = GetFrameView();
-  if (frame_view->GetVisible()) {
+  if (frame_view->GetFrameEnabled()) {
     gfx::Rect visible_bounds = ShellSurfaceBase::GetVisibleBounds();
     if (widget_->IsMaximized() && frame_type_ == SurfaceFrameType::NORMAL) {
       // When the widget is maximized in clamshell mode, client sends
@@ -1262,7 +1262,7 @@
           .work_area();
 
   ash::WindowState* window_state = GetWindowState();
-  bool enable_wide_frame = GetFrameView()->GetVisible() &&
+  bool enable_wide_frame = GetFrameView()->GetFrameEnabled() &&
                            window_state->IsMaximizedOrFullscreenOrPinned() &&
                            work_area.width() != geometry().width();
   bool update_frame = state_changed_;
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index e3011b64..fda415a1 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -515,7 +515,7 @@
 
   // Normal state.
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(normal_window_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(normal_window_bounds));
@@ -526,7 +526,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(
       gfx::Size(800, 568),
@@ -539,7 +539,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(gfx::Rect(0, 200, 800, 400), widget->GetWindowBoundsInScreen());
 
   display_manager->UpdateWorkAreaOfDisplay(display_id, gfx::Insets(0, 0, 0, 0));
@@ -550,7 +550,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(fullscreen_bounds,
             frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds));
@@ -560,7 +560,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(fullscreen_bounds,
             frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds));
@@ -585,7 +585,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_EQ(normal_window_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(normal_window_bounds));
@@ -597,7 +597,7 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_FALSE(frame_view->GetVisible());
+  EXPECT_FALSE(frame_view->GetFrameEnabled());
   EXPECT_EQ(client_bounds, widget->GetWindowBoundsInScreen());
   EXPECT_EQ(client_bounds,
             frame_view->GetClientBoundsForWindowBounds(client_bounds));
@@ -609,14 +609,14 @@
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
 
   surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
 
   widget->LayoutRootViewIfNecessary();
-  EXPECT_FALSE(frame_view->GetVisible());
+  EXPECT_FALSE(frame_view->GetFrameEnabled());
   EXPECT_FALSE(frame_view->GetHeaderView()->in_immersive_mode());
 }
 
@@ -2013,7 +2013,7 @@
   // Snapped window can also use auto hide.
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
   surface->Commit();
-  EXPECT_TRUE(frame_view->GetVisible());
+  EXPECT_TRUE(frame_view->GetFrameEnabled());
   EXPECT_TRUE(frame_view->GetHeaderView()->in_immersive_mode());
 }
 
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index a4ad9956..938d5c2 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -111,8 +111,7 @@
                   ShellSurfaceBase* shell_surface,
                   bool enabled)
       : NonClientFrameViewAsh(widget), shell_surface_(shell_surface) {
-    SetEnabled(enabled);
-    SetVisible(enabled);
+    SetFrameEnabled(enabled);
     if (!enabled)
       NonClientFrameViewAsh::SetShouldPaintHeader(false);
   }
@@ -121,7 +120,7 @@
 
   // Overridden from ash::NonClientFrameViewAsh:
   void SetShouldPaintHeader(bool paint) override {
-    if (GetVisible()) {
+    if (GetFrameEnabled()) {
       NonClientFrameViewAsh::SetShouldPaintHeader(paint);
       return;
     }
@@ -129,46 +128,46 @@
 
   // Overridden from views::NonClientFrameView:
   gfx::Rect GetBoundsForClientView() const override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::GetBoundsForClientView();
     return bounds();
   }
   gfx::Rect GetWindowBoundsForClientBounds(
       const gfx::Rect& client_bounds) const override {
-    if (GetVisible()) {
+    if (GetFrameEnabled()) {
       return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
           client_bounds);
     }
     return client_bounds;
   }
   int NonClientHitTest(const gfx::Point& point) override {
-    if (GetVisible() || shell_surface_->server_side_resize())
+    if (GetFrameEnabled() || shell_surface_->server_side_resize())
       return ash::NonClientFrameViewAsh::NonClientHitTest(point);
     return GetWidget()->client_view()->NonClientHitTest(point);
   }
   void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::GetWindowMask(size, window_mask);
   }
   void ResetWindowControls() override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::ResetWindowControls();
   }
   void UpdateWindowIcon() override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::ResetWindowControls();
   }
   void UpdateWindowTitle() override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::UpdateWindowTitle();
   }
   void SizeConstraintsChanged() override {
-    if (GetVisible())
+    if (GetFrameEnabled())
       return ash::NonClientFrameViewAsh::SizeConstraintsChanged();
   }
   gfx::Size GetMinimumSize() const override {
     gfx::Size minimum_size = shell_surface_->GetMinimumSize();
-    if (GetVisible()) {
+    if (GetFrameEnabled()) {
       return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
                  gfx::Rect(minimum_size))
           .size();
@@ -177,7 +176,7 @@
   }
   gfx::Size GetMaximumSize() const override {
     gfx::Size maximum_size = shell_surface_->GetMaximumSize();
-    if (GetVisible() && !maximum_size.IsEmpty()) {
+    if (GetFrameEnabled() && !maximum_size.IsEmpty()) {
       return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
                  gfx::Rect(maximum_size))
           .size();
@@ -705,11 +704,10 @@
 
   CustomFrameView* frame_view =
       static_cast<CustomFrameView*>(widget_->non_client_view()->frame_view());
-  if (frame_view->GetEnabled() == frame_enabled())
+  if (frame_view->GetFrameEnabled() == frame_enabled())
     return;
 
-  frame_view->SetEnabled(frame_enabled());
-  frame_view->SetVisible(frame_enabled());
+  frame_view->SetFrameEnabled(frame_enabled());
   frame_view->SetShouldPaintHeader(frame_enabled());
   widget_->GetRootView()->Layout();
   // TODO(oshima): We probably should wait applying these if the
diff --git a/components/feed/core/v2/BUILD.gn b/components/feed/core/v2/BUILD.gn
index bc300a0..36d433d 100644
--- a/components/feed/core/v2/BUILD.gn
+++ b/components/feed/core/v2/BUILD.gn
@@ -144,9 +144,13 @@
   testonly = true
   sources = [
     "algorithm_unittest.cc",
+    "api_test/feed_api_notice_card_unittest.cc",
+    "api_test/feed_api_offline_pages_unittest.cc",
+    "api_test/feed_api_stream_unittest.cc",
+    "api_test/feed_api_test.cc",
+    "api_test/feed_api_test.h",
     "feed_network_impl_unittest.cc",
     "feed_store_unittest.cc",
-    "feed_stream_unittest.cc",
     "feedstore_util_unittest.cc",
     "image_fetcher_unittest.cc",
     "metrics_reporter_unittest.cc",
diff --git a/components/feed/core/v2/api_test/README.md b/components/feed/core/v2/api_test/README.md
new file mode 100644
index 0000000..5f0c090
--- /dev/null
+++ b/components/feed/core/v2/api_test/README.md
@@ -0,0 +1,2 @@
+This directory is for tests of the Feed component which target the public
+FeedApi.
diff --git a/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
new file mode 100644
index 0000000..fdb99bf
--- /dev/null
+++ b/components/feed/core/v2/api_test/feed_api_notice_card_unittest.cc
@@ -0,0 +1,329 @@
+// 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 "base/test/metrics/histogram_tester.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "components/feed/core/v2/api_test/feed_api_test.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/core/v2/test/callback_receiver.h"
+#include "components/feed/feed_feature_list.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+namespace test {
+namespace {
+
+class FeedStreamConditionalActionsUploadTest : public FeedApiTest {
+  void SetupFeatures() override {
+    scoped_feature_list_.InitAndEnableFeature(
+        feed::kInterestFeedV2ClicksAndViewsConditionalUpload);
+  }
+};
+
+TEST_F(FeedApiTest, LoadStreamSendsNoticeCardAcknowledgement) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      feed::kInterestFeedNoticeCardAutoDismiss);
+
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Generate 3 view actions and 1 click action to trigger the acknowledgement
+  // of the notice card.
+  const int notice_card_index = 0;
+  std::string slice_id =
+      surface.initial_state->updated_slices(notice_card_index)
+          .slice()
+          .slice_id();
+  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
+                             slice_id);
+  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
+                             slice_id);
+  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
+                             slice_id);
+  stream_->ReportOpenAction(surface.GetStreamType(), slice_id);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->UnloadModel(surface.GetStreamType());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  WaitForIdleTaskQueue();
+
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .feed_query()
+                  .chrome_fulfillment_info()
+                  .notice_card_acknowledged());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       NoActionsUploadUntilReachedConditions) {
+  // Tests the flow where we:
+  //   (1) Perform a ThereAndBackAgain action and a View action while upload
+  //   isn't enabled => (2) Attempt an upload while the upload conditions aren't
+  //   reached => (3) Reach upload conditions => (4) Perform another View action
+  //   that should be dropped => (5) Simulate the backgrounding of the app to
+  //   enable actions upload => (6) Trigger an upload which will upload the
+  //   stored ThereAndBackAgain action.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Process the view action and the ThereAndBackAgain action while the upload
+  // conditions aren't reached.
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+  // Verify that the view action was dropped.
+  ASSERT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
+
+  stream_->ProcessThereAndBackAgain(
+      MakeThereAndBackAgainData(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+  // Verify that the ThereAndBackAgain action is in the action store.
+  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
+
+  // Attempt an upload.
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+  // Verify that no upload is done because the conditions aren't reached.
+  EXPECT_EQ(0, network_.GetActionRequestCount());
+
+  // Reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  // Verify that the view action is still dropped because we haven't
+  // transitioned out of the current surface.
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
+
+  // Enable the upload bit and trigger the upload of actions.
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+
+  // Verify that the ThereAndBackAgain action was uploaded but not the view
+  // action.
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnSurfaceAttached) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Perform a ThereAndBackAgain action.
+  stream_->ProcessThereAndBackAgain(
+      MakeThereAndBackAgainData(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+
+  // Reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  // Attach a new surface to update the bit to enable uploads.
+  TestForYouSurface surface2(stream_.get());
+
+  // Trigger an upload through load more to isolate the effect of the on-attach
+  // event on enabling uploads.
+  response_translator_.InjectResponse(MakeTypicalNextPageState());
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  // Verify that the ThereAndBackAgain action was uploaded.
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnEnterBackground) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Perform a ThereAndBackAgain action.
+  stream_->ProcessThereAndBackAgain(
+      MakeThereAndBackAgainData(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+
+  // Reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+
+  // Verify that the ThereAndBackAgain action was uploaded.
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       AllowActionsUploadWhenNoticeCardNotPresentRegardlessOfConditions) {
+  auto model_state = MakeTypicalInitialModelState();
+  model_state->stream_data.set_privacy_notice_fulfilled(false);
+  response_translator_.InjectResponse(std::move(model_state));
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Process the view action and the ThereAndBackAgain action while the upload
+  // conditions aren't reached.
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+  stream_->ProcessThereAndBackAgain(
+      MakeThereAndBackAgainData(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+
+  // Trigger an upload through a query.
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+
+  // Verify the ThereAndBackAgain action and the view action were uploaded.
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       ReupdateUploadEnableBitsOnSignIn) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  // Assert that uploads are not yet enabled.
+  ASSERT_FALSE(stream_->CanUploadActions());
+
+  // Update the upload enable bits which will enable upload because the related
+  // pref is true.
+  stream_->OnSignedIn();
+
+  EXPECT_TRUE(stream_->CanUploadActions());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       ResetTheUploadEnableBitsOnSignOut) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  // Update the upload enable bits which will enable upload.
+  stream_->OnSignedOut();
+
+  ASSERT_TRUE(stream_->CanUploadActions());
+}
+
+TEST_F(FeedApiTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
+  base::HistogramTester histograms;
+
+  // Trigger a stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(false);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+    WaitForIdleTaskQueue();
+  }
+
+  UnloadModel(kForYouStream);
+
+  // Trigger another stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(true);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+    WaitForIdleTaskQueue();
+  }
+
+  // Verify that the notice card fulfillment histogram was properly recorded.
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               0, 1);
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               1, 1);
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       DontTriggerActionsUploadWhenWasNotSignedIn) {
+  auto update_request = MakeTypicalInitialModelState();
+  update_request->stream_data.set_signed_in(false);
+  response_translator_.InjectResponse(std::move(update_request));
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Try to reach conditions.
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  // Try to trigger an upload through a query.
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+
+  // Verify that even if the conditions were reached, the pref that enables the
+  // upload wasn't set to true because the latest refresh request wasn't signed
+  // in.
+  ASSERT_FALSE(stream_->CanUploadActions());
+}
+
+TEST_F(FeedStreamConditionalActionsUploadTest,
+       LoadMoreDoesntUpdateNoticeCardPrefAndHistogram) {
+  // The initial stream load has the notice card.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Inject a response for the LoadMore fetch that doesn't have the notice card.
+  // It shouldn't overwrite the notice card pref.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(
+      /* page_number= */ 0,
+      /* last_added_time= */ kTestTimeEpoch,
+      /* signed_in= */ true,
+      /* logging_enabled= */ false));
+
+  // Start tracking histograms after the initial stream load to isolate the
+  // effect of load more.
+  base::HistogramTester histograms;
+
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  // Process a view action that should be dropped because the upload of actions
+  // is still disabled because there is still a notice card.
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+
+  // Trigger an upload.
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+
+  // Verify that there were no uploads.
+  EXPECT_EQ(0, network_.GetActionRequestCount());
+
+  // Verify that the notice card fulfillment histogram isn't recorded for load
+  // more.
+  histograms.ExpectTotalCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                              0);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_offline_pages_unittest.cc b/components/feed/core/v2/api_test/feed_api_offline_pages_unittest.cc
new file mode 100644
index 0000000..45fcac4
--- /dev/null
+++ b/components/feed/core/v2/api_test/feed_api_offline_pages_unittest.cc
@@ -0,0 +1,204 @@
+// 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 "base/test/metrics/histogram_tester.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "components/feed/core/v2/api_test/feed_api_test.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/core/v2/test/callback_receiver.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+namespace test {
+namespace {
+
+TEST_F(FeedApiTest, ProvidesPrefetchSuggestionsWhenModelLoaded) {
+  // Setup by triggering a model load.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Because we loaded from the network,
+  // PrefetchService::NewSuggestionsAvailable() should have been called.
+  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
+
+  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
+  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
+      callback.Bind());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(callback.GetResult());
+  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
+      callback.GetResult().value();
+
+  ASSERT_EQ(2UL, suggestions.size());
+  EXPECT_EQ("http://content0/", suggestions[0].article_url);
+  EXPECT_EQ("title0", suggestions[0].article_title);
+  EXPECT_EQ("publisher0", suggestions[0].article_attribution);
+  EXPECT_EQ("snippet0", suggestions[0].article_snippet);
+  EXPECT_EQ("http://image0/", suggestions[0].thumbnail_url);
+  EXPECT_EQ("http://favicon0/", suggestions[0].favicon_url);
+
+  EXPECT_EQ("http://content1/", suggestions[1].article_url);
+}
+
+TEST_F(FeedApiTest, ProvidesPrefetchSuggestionsWhenModelNotLoaded) {
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+
+  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
+  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
+      callback.Bind());
+  WaitForIdleTaskQueue();
+
+  ASSERT_FALSE(stream_->GetModel(kForYouStream));
+  ASSERT_TRUE(callback.GetResult());
+  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
+      callback.GetResult().value();
+
+  ASSERT_EQ(2UL, suggestions.size());
+  EXPECT_EQ("http://content0/", suggestions[0].article_url);
+  EXPECT_EQ("http://content1/", suggestions[1].article_url);
+  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
+}
+
+TEST_F(FeedApiTest, ScrubsUrlsInProvidedPrefetchSuggestions) {
+  {
+    auto initial_state = MakeTypicalInitialModelState();
+    initial_state->content[0].mutable_prefetch_metadata(0)->set_uri(
+        "?notavalidurl?");
+    initial_state->content[0].mutable_prefetch_metadata(0)->set_image_url(
+        "?asdf?");
+    initial_state->content[0].mutable_prefetch_metadata(0)->set_favicon_url(
+        "?hi?");
+    initial_state->content[0].mutable_prefetch_metadata(0)->clear_uri();
+    store_->OverwriteStream(kForYouStream, std::move(initial_state),
+                            base::DoNothing());
+  }
+
+  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
+  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
+      callback.Bind());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(callback.GetResult());
+  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
+      callback.GetResult().value();
+
+  ASSERT_EQ(2UL, suggestions.size());
+  EXPECT_EQ("", suggestions[0].article_url.possibly_invalid_spec());
+  EXPECT_EQ("", suggestions[0].thumbnail_url.possibly_invalid_spec());
+  EXPECT_EQ("", suggestions[0].favicon_url.possibly_invalid_spec());
+}
+
+TEST_F(FeedApiTest, OfflineBadgesArePopulatedInitially) {
+  // Add two offline pages. We exclude tab-bound pages, so only the first is
+  // used.
+  offline_page_model_.AddTestPage(GURL("http://content0/"));
+  offline_page_model_.AddTestPage(GURL("http://content1/"));
+  offline_page_model_.items()[1].client_id.name_space =
+      offline_pages::kLastNNamespace;
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ((std::map<std::string, std::string>(
+                {{"app/badge0", SerializedOfflineBadgeContent()}})),
+            surface.GetDataStoreEntries());
+}
+
+TEST_F(FeedApiTest, OfflineBadgesArePopulatedOnNewOfflineItemAdded) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ((std::map<std::string, std::string>({})),
+            surface.GetDataStoreEntries());
+
+  // Add an offline page.
+  offline_page_model_.AddTestPage(GURL("http://content1/"));
+  offline_page_model_.CallObserverOfflinePageAdded(
+      offline_page_model_.items()[0]);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+
+  EXPECT_EQ((std::map<std::string, std::string>(
+                {{"app/badge1", SerializedOfflineBadgeContent()}})),
+            surface.GetDataStoreEntries());
+}
+
+TEST_F(FeedApiTest, OfflineBadgesAreRemovedWhenOfflineItemRemoved) {
+  offline_page_model_.AddTestPage(GURL("http://content0/"));
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ((std::map<std::string, std::string>(
+                {{"app/badge0", SerializedOfflineBadgeContent()}})),
+            surface.GetDataStoreEntries());
+
+  // Remove the offline page.
+  offline_page_model_.CallObserverOfflinePageDeleted(
+      offline_page_model_.items()[0]);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+
+  EXPECT_EQ((std::map<std::string, std::string>()),
+            surface.GetDataStoreEntries());
+}
+
+TEST_F(FeedApiTest, OfflineBadgesAreProvidedToNewSurfaces) {
+  offline_page_model_.AddTestPage(GURL("http://content0/"));
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  TestForYouSurface surface2(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ((std::map<std::string, std::string>(
+                {{"app/badge0", SerializedOfflineBadgeContent()}})),
+            surface2.GetDataStoreEntries());
+}
+
+TEST_F(FeedApiTest, OfflineBadgesAreRemovedWhenModelIsUnloaded) {
+  offline_page_model_.AddTestPage(GURL("http://content0/"));
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->UnloadModel(surface.GetStreamType());
+
+  // Offline badge no longer present.
+  EXPECT_EQ((std::map<std::string, std::string>()),
+            surface.GetDataStoreEntries());
+}
+
+TEST_F(FeedApiTest, MultipleOfflineBadgesWithSameUrl) {
+  {
+    std::unique_ptr<StreamModelUpdateRequest> state =
+        MakeTypicalInitialModelState();
+    const feedwire::PrefetchMetadata& prefetch_metadata1 =
+        state->content[0].prefetch_metadata(0);
+    feedwire::PrefetchMetadata& prefetch_metadata2 =
+        *state->content[0].add_prefetch_metadata();
+    prefetch_metadata2 = prefetch_metadata1;
+    prefetch_metadata2.set_badge_id("app/badge0b");
+    response_translator_.InjectResponse(std::move(state));
+  }
+  offline_page_model_.AddTestPage(GURL("http://content0/"));
+
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ((std::map<std::string, std::string>(
+                {{"app/badge0", SerializedOfflineBadgeContent()},
+                 {"app/badge0b", SerializedOfflineBadgeContent()}})),
+            surface.GetDataStoreEntries());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_stream_unittest.cc b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
new file mode 100644
index 0000000..54145d5
--- /dev/null
+++ b/components/feed/core/v2/api_test/feed_api_stream_unittest.cc
@@ -0,0 +1,1970 @@
+// 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 "base/test/metrics/histogram_tester.h"
+#include "base/test/metrics/user_action_tester.h"
+#include "components/feed/core/v2/api_test/feed_api_test.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/core/v2/feedstore_util.h"
+#include "components/feed/core/v2/test/callback_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// This file is primarily for testing access to the Feed content, though it
+// contains some other miscellaneous tests.
+
+namespace feed {
+namespace test {
+namespace {
+
+TEST_F(FeedApiTest, IsArticlesListVisibleByDefault) {
+  EXPECT_TRUE(stream_->IsArticlesListVisible());
+}
+
+TEST_F(FeedApiTest, DoNotRefreshIfArticlesListIsHidden) {
+  profile_prefs_.SetBoolean(prefs::kArticlesListVisible, false);
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  EXPECT_FALSE(refresh_scheduler_.scheduled_run_times.count(
+      RefreshTaskId::kRefreshForYouFeed));
+  EXPECT_EQ(std::set<RefreshTaskId>({RefreshTaskId::kRefreshForYouFeed}),
+            refresh_scheduler_.completed_tasks);
+}
+
+TEST_F(FeedApiTest, BackgroundRefreshForYouSuccess) {
+  // Trigger a background refresh.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  WaitForIdleTaskQueue();
+
+  // Verify the refresh happened and that we can load a stream without the
+  // network.
+  ASSERT_TRUE(refresh_scheduler_.completed_tasks.count(
+      RefreshTaskId::kRefreshForYouFeed));
+  EXPECT_EQ(LoadStreamStatus::kLoadedFromNetwork,
+            metrics_reporter_->background_refresh_status);
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+  EXPECT_FALSE(stream_->GetModel(kForYouStream));
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  // Verify that prefetch service was informed.
+  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
+}
+
+TEST_F(FeedApiTest, BackgroundRefreshWebFeedSuccess) {
+  // Trigger a background refresh.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshWebFeed);
+  WaitForIdleTaskQueue();
+
+  // Verify the refresh happened and that we can load a stream without the
+  // network.
+  ASSERT_TRUE(
+      refresh_scheduler_.completed_tasks.count(RefreshTaskId::kRefreshWebFeed));
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+  TestWebFeedSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  // Verify that prefetch service is NOT informed.
+  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
+}
+
+TEST_F(FeedApiTest, BackgroundRefreshPrefetchesImages) {
+  // Trigger a background refresh.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  EXPECT_EQ(0, prefetch_image_call_count_);
+  WaitForIdleTaskQueue();
+
+  std::vector<GURL> expected_fetches(
+      {GURL("http://image0/"), GURL("http://favicon0/"), GURL("http://image1/"),
+       GURL("http://favicon1/")});
+  // Verify that images were prefetched.
+  EXPECT_EQ(4, prefetch_image_call_count_);
+  EXPECT_EQ(expected_fetches, prefetched_images_);
+}
+
+TEST_F(FeedApiTest, BackgroundRefreshNotAttemptedWhenModelIsLoading) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(metrics_reporter_->background_refresh_status,
+            LoadStreamStatus::kModelAlreadyLoaded);
+}
+
+TEST_F(FeedApiTest, BackgroundRefreshNotAttemptedAfterModelIsLoaded) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(metrics_reporter_->background_refresh_status,
+            LoadStreamStatus::kModelAlreadyLoaded);
+}
+
+TEST_F(FeedApiTest, SurfaceReceivesInitialContent) {
+  {
+    auto model = std::make_unique<StreamModel>();
+    model->Update(MakeTypicalInitialModelState());
+    stream_->LoadModelForTesting(kForYouStream, std::move(model));
+  }
+  TestForYouSurface surface(stream_.get());
+  ASSERT_TRUE(surface.initial_state);
+  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
+  ASSERT_EQ(2, initial_state.updated_slices().size());
+  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
+  EXPECT_EQ("f:0", initial_state.updated_slices(0)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
+  EXPECT_EQ("f:1", initial_state.updated_slices(1)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+  ASSERT_EQ(1, initial_state.new_shared_states().size());
+  EXPECT_EQ("ss:0",
+            initial_state.new_shared_states()[0].xsurface_shared_state());
+}
+
+TEST_F(FeedApiTest, SurfaceReceivesInitialContentLoadedAfterAttach) {
+  TestForYouSurface surface(stream_.get());
+  ASSERT_FALSE(surface.initial_state);
+  {
+    auto model = std::make_unique<StreamModel>();
+    model->Update(MakeTypicalInitialModelState());
+    stream_->LoadModelForTesting(kForYouStream, std::move(model));
+  }
+
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
+
+  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
+  EXPECT_EQ("f:0", initial_state.updated_slices(0)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
+  EXPECT_EQ("f:1", initial_state.updated_slices(1)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+  ASSERT_EQ(1, initial_state.new_shared_states().size());
+  EXPECT_EQ("ss:0",
+            initial_state.new_shared_states()[0].xsurface_shared_state());
+}
+
+TEST_F(FeedApiTest, SurfaceReceivesUpdatedContent) {
+  {
+    auto model = std::make_unique<StreamModel>();
+    model->ExecuteOperations(MakeTypicalStreamOperations());
+    stream_->LoadModelForTesting(kForYouStream, std::move(model));
+  }
+  TestForYouSurface surface(stream_.get());
+  // Remove #1, add #2.
+  stream_->ExecuteOperations(
+      kForYouStream, {
+                         MakeOperation(MakeRemove(MakeClusterId(1))),
+                         MakeOperation(MakeCluster(2, MakeRootId())),
+                         MakeOperation(MakeContentNode(2, MakeClusterId(2))),
+                         MakeOperation(MakeContent(2)),
+                     });
+  ASSERT_TRUE(surface.update);
+  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
+  const feedui::StreamUpdate& update = surface.update.value();
+
+  ASSERT_EQ("2 slices -> 2 slices", surface.DescribeUpdates());
+  // First slice is just an ID that matches the old 1st slice ID.
+  EXPECT_EQ(initial_state.updated_slices(0).slice().slice_id(),
+            update.updated_slices(0).slice_id());
+  // Second slice is a new xsurface slice.
+  EXPECT_NE("", update.updated_slices(1).slice().slice_id());
+  EXPECT_EQ("f:2",
+            update.updated_slices(1).slice().xsurface_slice().xsurface_frame());
+}
+
+TEST_F(FeedApiTest, SurfaceReceivesSecondUpdatedContent) {
+  {
+    auto model = std::make_unique<StreamModel>();
+    model->ExecuteOperations(MakeTypicalStreamOperations());
+    stream_->LoadModelForTesting(kForYouStream, std::move(model));
+  }
+  TestForYouSurface surface(stream_.get());
+  // Add #2.
+  stream_->ExecuteOperations(
+      kForYouStream, {
+                         MakeOperation(MakeCluster(2, MakeRootId())),
+                         MakeOperation(MakeContentNode(2, MakeClusterId(2))),
+                         MakeOperation(MakeContent(2)),
+                     });
+
+  // Clear the last update and add #3.
+  stream_->ExecuteOperations(
+      kForYouStream, {
+                         MakeOperation(MakeCluster(3, MakeRootId())),
+                         MakeOperation(MakeContentNode(3, MakeClusterId(3))),
+                         MakeOperation(MakeContent(3)),
+                     });
+
+  // The last update should have only one new piece of content.
+  // This verifies the current content set is tracked properly.
+  ASSERT_EQ("2 slices -> 3 slices -> 4 slices", surface.DescribeUpdates());
+
+  ASSERT_EQ(4, surface.update->updated_slices().size());
+  EXPECT_FALSE(surface.update->updated_slices(0).has_slice());
+  EXPECT_FALSE(surface.update->updated_slices(1).has_slice());
+  EXPECT_FALSE(surface.update->updated_slices(2).has_slice());
+  EXPECT_EQ("f:3", surface.update->updated_slices(3)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+}
+
+TEST_F(FeedApiTest, RemoveAllContentResultsInZeroState) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Remove both pieces of content.
+  stream_->ExecuteOperations(kForYouStream,
+                             {
+                                 MakeOperation(MakeRemove(MakeClusterId(0))),
+                                 MakeOperation(MakeRemove(MakeClusterId(1))),
+                             });
+
+  ASSERT_EQ("loading -> 2 slices -> no-cards", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, DetachSurface) {
+  {
+    auto model = std::make_unique<StreamModel>();
+    model->ExecuteOperations(MakeTypicalStreamOperations());
+    stream_->LoadModelForTesting(kForYouStream, std::move(model));
+  }
+  TestForYouSurface surface(stream_.get());
+  EXPECT_TRUE(surface.initial_state);
+  surface.Detach();
+  surface.Clear();
+
+  // Arbitrary stream change. Surface should not see the update.
+  stream_->ExecuteOperations(kForYouStream,
+                             {
+                                 MakeOperation(MakeRemove(MakeClusterId(1))),
+                             });
+  EXPECT_FALSE(surface.update);
+}
+
+TEST_F(FeedApiTest, FetchImage) {
+  CallbackReceiver<NetworkResponse> receiver;
+  stream_->FetchImage(GURL("https://example.com"), receiver.Bind());
+
+  EXPECT_EQ("dummyresponse", receiver.GetResult()->response_bytes);
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, LoadFromNetwork) {
+  {
+    auto metadata = stream_->GetMetadata();
+    metadata.set_consistency_token("token");
+    stream_->SetMetadata(metadata);
+  }
+
+  // Store is empty, so we should fallback to a network request.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_TRUE(network_.query_request_sent);
+  EXPECT_EQ(
+      "token",
+      network_.query_request_sent->feed_request().consistency_token().token());
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  // Verify the model is filled correctly.
+  EXPECT_STRINGS_EQUAL(
+      ModelStateFor(MakeTypicalInitialModelState()),
+      stream_->GetModel(GetStreamType())->DumpStateForTesting());
+  // Verify the data was written to the store.
+  EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()),
+                       ModelStateFor(GetStreamType(), store_.get()));
+}
+
+TEST_F(FeedApiTest, ForceRefreshForDebugging) {
+  // First do a normal load via network that will fail.
+  is_offline_ = true;
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Next, force a refresh that results in a successful load.
+  is_offline_ = false;
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->ForceRefreshForDebugging();
+
+  WaitForIdleTaskQueue();
+  EXPECT_EQ("loading -> cant-refresh -> loading -> 2 slices",
+            surface.DescribeUpdates());
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, RefreshScheduleFlow) {
+  // Inject a typical network response, with a server-defined request schedule.
+  {
+    RequestSchedule schedule;
+    schedule.anchor_time = kTestTimeEpoch;
+    schedule.refresh_offsets = {base::TimeDelta::FromSeconds(12),
+                                base::TimeDelta::FromSeconds(48)};
+    RefreshResponseData response_data;
+    response_data.model_update_request = MakeTypicalInitialModelState();
+    response_data.request_schedule = schedule;
+
+    response_translator_.InjectResponse(std::move(response_data));
+
+    // Load the stream, and then destroy the surface to allow background
+    // refresh.
+    TestSurface surface(stream_.get());
+    WaitForIdleTaskQueue();
+    UnloadModel(surface.GetStreamType());
+  }
+
+  // Verify the first refresh was scheduled.
+  EXPECT_EQ(base::TimeDelta::FromSeconds(12),
+            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
+
+  // Simulate executing the background task.
+  refresh_scheduler_.Clear();
+  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(12));
+  stream_->ExecuteRefreshTask(GetRefreshTaskId());
+  WaitForIdleTaskQueue();
+
+  // Verify |RefreshTaskComplete()| was called and next refresh was scheduled.
+  EXPECT_TRUE(refresh_scheduler_.completed_tasks.count(GetRefreshTaskId()));
+  EXPECT_EQ(base::TimeDelta::FromSeconds(48 - 12),
+            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
+
+  // Simulate executing the background task again.
+  refresh_scheduler_.Clear();
+  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(48 - 12));
+  stream_->ExecuteRefreshTask(GetRefreshTaskId());
+  WaitForIdleTaskQueue();
+
+  // Verify |RefreshTaskComplete()| was called and next refresh was scheduled.
+  EXPECT_TRUE(refresh_scheduler_.completed_tasks.count(GetRefreshTaskId()));
+  EXPECT_EQ(GetFeedConfig().default_background_refresh_interval,
+            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
+}
+
+TEST_F(FeedApiTest, ForceRefreshIfMissedScheduledRefresh) {
+  // Inject a typical network response, with a server-defined request schedule.
+  {
+    RequestSchedule schedule;
+    schedule.anchor_time = kTestTimeEpoch;
+    schedule.refresh_offsets = {base::TimeDelta::FromSeconds(12),
+                                base::TimeDelta::FromSeconds(48)};
+    RefreshResponseData response_data;
+    response_data.model_update_request = MakeTypicalInitialModelState();
+    response_data.request_schedule = schedule;
+
+    response_translator_.InjectResponse(std::move(response_data));
+  }
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);
+  surface.Detach();
+  stream_->UnloadModel(surface.GetStreamType());
+
+  // Ensure a refresh is foreced only after a scheduled refresh was missed.
+  // First, load the stream after 11 seconds.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(11));
+  surface.Attach(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);  // no refresh yet
+
+  // Load the stream after 13 seconds. We missed the scheduled refresh at
+  // 12 seconds.
+  surface.Detach();
+  stream_->UnloadModel(surface.GetStreamType());
+  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(2));
+  surface.Attach(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(2, network_.send_query_call_count);
+  EXPECT_EQ(LoadStreamStatus::kDataInStoreStaleMissedLastRefresh,
+            metrics_reporter_->load_stream_from_store_status);
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, LoadFromNetworkBecauseStoreIsStale) {
+  // Fill the store with stream data that is just barely stale, and verify we
+  // fetch new data over the network.
+  store_->OverwriteStream(
+      GetStreamType(),
+      MakeTypicalInitialModelState(
+          /*first_cluster_id=*/0, kTestTimeEpoch -
+                                      GetFeedConfig().stale_content_threshold -
+                                      base::TimeDelta::FromMinutes(1)),
+      base::DoNothing());
+
+  // Store is stale, so we should fallback to a network request.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(network_.query_request_sent);
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+  ASSERT_TRUE(surface.initial_state);
+}
+
+// Same as LoadFromNetworkBecauseStoreIsStale, but with expired content.
+TEST_F(FeedApiTest, LoadFromNetworkBecauseStoreIsExpired) {
+  base::HistogramTester histograms;
+  const base::TimeDelta kContentAge =
+      GetFeedConfig().content_expiration_threshold +
+      base::TimeDelta::FromMinutes(1);
+  store_->OverwriteStream(
+      kForYouStream,
+      MakeTypicalInitialModelState(
+          /*first_cluster_id=*/0, kTestTimeEpoch - kContentAge),
+      base::DoNothing());
+
+  // Store is stale, so we should fallback to a network request.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(network_.query_request_sent);
+  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
+  ASSERT_TRUE(surface.initial_state);
+  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsExpired,
+            metrics_reporter_->load_stream_from_store_status);
+  histograms.ExpectUniqueTimeSample(
+      "ContentSuggestions.Feed.ContentAgeOnLoad.BlockingRefresh", kContentAge,
+      1);
+}
+
+TEST_F(FeedApiTest, LoadStaleDataBecauseNetworkRequestFails) {
+  // Fill the store with stream data that is just barely stale.
+  base::HistogramTester histograms;
+  const base::TimeDelta kContentAge =
+      GetFeedConfig().stale_content_threshold + base::TimeDelta::FromMinutes(1);
+  store_->OverwriteStream(
+      kForYouStream,
+      MakeTypicalInitialModelState(
+          /*first_cluster_id=*/0, kTestTimeEpoch - kContentAge),
+      base::DoNothing());
+
+  // Store is stale, so we should fallback to a network request. Since we didn't
+  // inject a network response, the network update will fail.
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(network_.query_request_sent);
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsStale,
+            metrics_reporter_->load_stream_from_store_status);
+  EXPECT_EQ(LoadStreamStatus::kLoadedStaleDataFromStoreDueToNetworkFailure,
+            metrics_reporter_->load_stream_status);
+  histograms.ExpectUniqueTimeSample(
+      "ContentSuggestions.Feed.ContentAgeOnLoad.NotRefreshed", kContentAge, 1);
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, LoadFailsStoredDataIsExpired) {
+  // Fill the store with stream data that is just barely expired.
+  store_->OverwriteStream(
+      GetStreamType(),
+      MakeTypicalInitialModelState(
+          /*first_cluster_id=*/0,
+          kTestTimeEpoch - GetFeedConfig().content_expiration_threshold -
+              base::TimeDelta::FromMinutes(1)),
+      base::DoNothing());
+
+  // Store contains expired content, so we should fallback to a network request.
+  // Since we didn't inject a network response, the network update will fail.
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_TRUE(network_.query_request_sent);
+  EXPECT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
+  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsExpired,
+            metrics_reporter_->load_stream_from_store_status);
+  EXPECT_EQ(LoadStreamStatus::kProtoTranslationFailed,
+            metrics_reporter_->load_stream_status);
+}
+
+TEST_F(FeedApiTest, LoadFromNetworkFailsDueToProtoTranslation) {
+  // No data in the store, so we should fetch from the network.
+  // The network will respond with an empty response, which should fail proto
+  // translation.
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(LoadStreamStatus::kProtoTranslationFailed,
+            metrics_reporter_->load_stream_status);
+  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
+}
+TEST_F(FeedApiTest, DoNotLoadFromNetworkWhenOffline) {
+  is_offline_ = true;
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(LoadStreamStatus::kCannotLoadFromNetworkOffline,
+            metrics_reporter_->load_stream_status);
+  EXPECT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, DoNotLoadStreamWhenArticleListIsHidden) {
+  profile_prefs_.SetBoolean(prefs::kArticlesListVisible, false);
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(LoadStreamStatus::kLoadNotAllowedArticlesListHidden,
+            metrics_reporter_->load_stream_status);
+  EXPECT_EQ("no-cards", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, DoNotLoadStreamWhenEulaIsNotAccepted) {
+  is_eula_accepted_ = false;
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(LoadStreamStatus::kLoadNotAllowedEulaNotAccepted,
+            metrics_reporter_->load_stream_status);
+  EXPECT_EQ("no-cards", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, LoadStreamAfterEulaIsAccepted) {
+  // Connect a surface before the EULA is accepted.
+  is_eula_accepted_ = false;
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("no-cards", surface.DescribeUpdates());
+
+  // Accept EULA, our surface should receive data.
+  is_eula_accepted_ = true;
+  stream_->OnEulaAccepted();
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
+  stream_->OnAllHistoryDeleted();
+
+  const std::string kSessionId = "session-id";
+
+  // This test injects response post translation/parsing. We have to configure
+  // the response data that should come out of the translator, which should
+  // mark the request/response as having been made from the signed-out state.
+  StreamModelUpdateRequestGenerator model_generator;
+  model_generator.signed_in = false;
+
+  // Advance the clock, but not past the end of the forced-signed-out period.
+  task_environment_.FastForwardBy(kSuppressRefreshDuration -
+                                  base::TimeDelta::FromSeconds(1));
+
+  // Refresh the feed, queuing up a signed-out response.
+  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+                                      kSessionId);
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Validate that the network request was sent as signed out.
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_TRUE(network_.forced_signed_out_request);
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .chrome_client_info()
+                  .session_id()
+                  .empty());
+
+  // Validate the downstream consumption of the response.
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
+  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
+
+  // Advance the clock beyond the forced signed out period.
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
+
+  // Requests for subsequent pages continue the use existing session.
+  // Subsequent responses may omit the session id.
+  response_translator_.InjectResponse(model_generator.MakeNextPage());
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  // Validate that the network request was sent as signed out and
+  // contained the session id.
+  ASSERT_EQ(2, network_.send_query_call_count);
+  EXPECT_TRUE(network_.forced_signed_out_request);
+  EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
+  EXPECT_EQ(network_.query_request_sent->feed_request()
+                .client_info()
+                .chrome_client_info()
+                .session_id(),
+            kSessionId);
+
+  // The model should still be in the signed-out state.
+  EXPECT_FALSE(stream_->GetModel(kForYouStream)->signed_in());
+
+  // Force a refresh of the feed by clearing the cache. The request for the
+  // first page should revert back to signed-in. The response data will denote
+  // a signed-in response with no session_id.
+  model_generator.signed_in = true;
+  response_translator_.InjectResponse(model_generator.MakeFirstPage());
+  stream_->OnCacheDataCleared();
+  WaitForIdleTaskQueue();
+
+  // Validate that a signed-in request was sent.
+  ASSERT_EQ(3, network_.send_query_call_count);
+  EXPECT_FALSE(network_.forced_signed_out_request);
+
+  // The model should now be in the signed-in state.
+  EXPECT_TRUE(stream_->GetModel(kForYouStream)->signed_in());
+  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
+}
+
+TEST_F(FeedApiTest, WebFeedUsesSignedInRequestAfterHistoryIsDeleted) {
+  stream_->OnAllHistoryDeleted();
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestWebFeedSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_FALSE(network_.forced_signed_out_request);
+}
+
+TEST_F(FeedApiTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
+  stream_->OnAllHistoryDeleted();
+  task_environment_.FastForwardBy(kSuppressRefreshDuration +
+                                  base::TimeDelta::FromSeconds(1));
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  EXPECT_FALSE(network_.forced_signed_out_request);
+  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
+}
+
+TEST_F(FeedApiTest, ShouldMakeFeedQueryRequestConsumesQuota) {
+  LoadStreamStatus status = LoadStreamStatus::kNoStatus;
+  for (; status == LoadStreamStatus::kNoStatus;
+       status = stream_->ShouldMakeFeedQueryRequest(kForYouStream)) {
+  }
+
+  ASSERT_EQ(LoadStreamStatus::kCannotLoadFromNetworkThrottled, status);
+}
+
+TEST_F(FeedApiTest, LoadStreamFromStore) {
+  // Fill the store with stream data that is just barely fresh, and verify it
+  // loads.
+  store_->OverwriteStream(
+      kForYouStream,
+      MakeTypicalInitialModelState(
+          /*first_cluster_id=*/0, kTestTimeEpoch -
+                                      GetFeedConfig().stale_content_threshold +
+                                      base::TimeDelta::FromMinutes(1)),
+      base::DoNothing());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  EXPECT_FALSE(network_.query_request_sent);
+  // Verify the model is filled correctly.
+  EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()),
+                       stream_->GetModel(kForYouStream)->DumpStateForTesting());
+}
+
+TEST_F(FeedApiTest, LoadingSpinnerIsSentInitially) {
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+  TestForYouSurface surface(stream_.get());
+
+  ASSERT_EQ("loading", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, DetachSurfaceWhileLoadingModel) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  surface.Detach();
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ("loading", surface.DescribeUpdates());
+  EXPECT_TRUE(network_.query_request_sent);
+}
+
+TEST_F(FeedApiTest, AttachMultipleSurfacesLoadsModelOnce) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  TestForYouSurface other_surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(1, network_.send_query_call_count);
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  ASSERT_EQ("loading -> 2 slices", other_surface.DescribeUpdates());
+
+  // After load, another surface doesn't trigger any tasks,
+  // and immediately has content.
+  TestForYouSurface later_surface(stream_.get());
+
+  ASSERT_EQ("2 slices", later_surface.DescribeUpdates());
+  EXPECT_TRUE(IsTaskQueueIdle());
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, ModelChangesAreSavedToStorage) {
+  store_->OverwriteStream(GetStreamType(), MakeTypicalInitialModelState(),
+                          base::DoNothing());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_TRUE(surface.initial_state);
+
+  // Remove #1, add #2.
+  const std::vector<feedstore::DataOperation> operations = {
+      MakeOperation(MakeRemove(MakeClusterId(1))),
+      MakeOperation(MakeCluster(2, MakeRootId())),
+      MakeOperation(MakeContentNode(2, MakeClusterId(2))),
+      MakeOperation(MakeContent(2)),
+  };
+  stream_->ExecuteOperations(GetStreamType(), operations);
+
+  WaitForIdleTaskQueue();
+
+  // Verify changes are applied to storage.
+  EXPECT_STRINGS_EQUAL(
+      ModelStateFor(MakeTypicalInitialModelState(), operations),
+      ModelStateFor(GetStreamType(), store_.get()));
+
+  // Unload and reload the model from the store, and verify we can still apply
+  // operations correctly.
+  surface.Detach();
+  surface.Clear();
+  UnloadModel(GetStreamType());
+  surface.Attach(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_TRUE(surface.initial_state);
+
+  // Remove #2, add #3.
+  const std::vector<feedstore::DataOperation> operations2 = {
+      MakeOperation(MakeRemove(MakeClusterId(2))),
+      MakeOperation(MakeCluster(3, MakeRootId())),
+      MakeOperation(MakeContentNode(3, MakeClusterId(3))),
+      MakeOperation(MakeContent(3)),
+  };
+  stream_->ExecuteOperations(surface.GetStreamType(), operations2);
+
+  WaitForIdleTaskQueue();
+  EXPECT_STRINGS_EQUAL(
+      ModelStateFor(MakeTypicalInitialModelState(), operations, operations2),
+      ModelStateFor(GetStreamType(), store_.get()));
+}
+
+TEST_F(FeedApiTest, ReportSliceViewedIdentifiesCorrectIndex) {
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+  EXPECT_EQ(1, metrics_reporter_->slice_viewed_index);
+}
+
+TEST_F(FeedApiTest, ReportOpenInNewTabAction) {
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  base::UserActionTester user_actions;
+
+  stream_->ReportOpenInNewTabAction(
+      surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+
+  EXPECT_EQ(1, user_actions.GetActionCount(
+                   "ContentSuggestions.Feed.CardAction.OpenInNewTab"));
+}
+
+TEST_F(FeedApiTest, HasUnreadContentAfterLoadFromNetwork) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestUnreadContentObserver observer;
+  stream_->AddUnreadContentObserver(kForYouStream, &observer);
+  TestForYouSurface surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(std::vector<bool>({true}), observer.calls);
+}
+
+TEST_F(FeedApiTest, RemovedUnreadContentObserverDoesNotReceiveCalls) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestUnreadContentObserver observer;
+  stream_->AddUnreadContentObserver(kForYouStream, &observer);
+  stream_->RemoveUnreadContentObserver(kForYouStream, &observer);
+  TestForYouSurface surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(std::vector<bool>(), observer.calls);
+}
+
+TEST_F(FeedApiTest, DeletedUnreadContentObserverDoesNotCrash) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  {
+    TestUnreadContentObserver observer;
+    stream_->AddUnreadContentObserver(kForYouStream, &observer);
+  }
+  TestForYouSurface surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+}
+
+TEST_F(FeedApiTest, HasUnreadContentAfterLoadFromStore) {
+  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
+                          base::DoNothing());
+
+  TestUnreadContentObserver observer;
+  stream_->AddUnreadContentObserver(kForYouStream, &observer);
+  TestForYouSurface surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(std::vector<bool>({true}), observer.calls);
+}
+
+TEST_F(FeedApiTest, ReportSliceViewedUpdatesObservers) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestUnreadContentObserver observer;
+  stream_->AddUnreadContentObserver(kForYouStream, &observer);
+  TestForYouSurface surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  stream_->ReportSliceViewed(
+      surface.GetSurfaceId(), surface.GetStreamType(),
+      surface.initial_state->updated_slices(1).slice().slice_id());
+  task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(std::vector<bool>({true, false}), observer.calls);
+
+  // Verify that the fact the stream was viewed persists.
+  CreateStream();
+
+  TestUnreadContentObserver observer2;
+  stream_->AddUnreadContentObserver(kForYouStream, &observer2);
+  TestForYouSurface surface2(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(std::vector<bool>({false}), observer2.calls);
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, LoadMoreAppendsContent) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  // Load page 2.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+  // Ensure metrics reporter was informed at the start of the operation.
+  EXPECT_EQ(surface.GetSurfaceId(), metrics_reporter_->load_more_surface_id);
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+  EXPECT_EQ("2 slices +spinner -> 4 slices", surface.DescribeUpdates());
+
+  // Load page 3.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
+  stream_->LoadMore(surface, callback.Bind());
+
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+  EXPECT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
+  if (GetStreamType().IsForYou()) {
+    EXPECT_EQ(3, prefetch_service_.NewSuggestionsAvailableCallCount());
+  } else {
+    EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
+  }
+}
+
+TEST_P(FeedStreamTestForAllStreamTypes, LoadMorePersistsData) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  // Load page 2.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+
+  // Verify stored state is equivalent to in-memory model.
+  EXPECT_STRINGS_EQUAL(
+      stream_->GetModel(GetStreamType())->DumpStateForTesting(),
+      ModelStateFor(GetStreamType(), store_.get()));
+}
+
+TEST_F(FeedApiTest, LoadMorePersistAndLoadMore) {
+  // Verify we can persist a LoadMore, and then do another LoadMore after
+  // reloading state.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  // Load page 2.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+
+  surface.Detach();
+  UnloadModel(kForYouStream);
+
+  // Load page 3.
+  surface.Attach(stream_.get());
+  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
+  WaitForIdleTaskQueue();
+  callback.Clear();
+  surface.Clear();
+  stream_->LoadMore(surface, callback.Bind());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+  ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
+  // Verify stored state is equivalent to in-memory model.
+  EXPECT_STRINGS_EQUAL(
+      stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(),
+      ModelStateFor(kForYouStream, store_.get()));
+}
+
+TEST_F(FeedApiTest, LoadMoreSendsTokens) {
+  {
+    auto metadata = stream_->GetMetadata();
+    metadata.set_consistency_token("token");
+    stream_->SetMetadata(metadata);
+  }
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("2 slices +spinner -> 4 slices", surface.DescribeUpdates());
+
+  EXPECT_EQ(
+      "token",
+      network_.query_request_sent->feed_request().consistency_token().token());
+  EXPECT_EQ("page-2", network_.query_request_sent->feed_request()
+                          .feed_query()
+                          .next_page_token()
+                          .next_page_token()
+                          .next_page_token());
+
+  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
+  stream_->LoadMore(surface, callback.Bind());
+
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
+
+  EXPECT_EQ(
+      "token",
+      network_.query_request_sent->feed_request().consistency_token().token());
+  EXPECT_EQ("page-3", network_.query_request_sent->feed_request()
+                          .feed_query()
+                          .next_page_token()
+                          .next_page_token()
+                          .next_page_token());
+}
+
+TEST_F(FeedApiTest, LoadMoreAbortsIfNoNextPageToken) {
+  {
+    std::unique_ptr<StreamModelUpdateRequest> initial_state =
+        MakeTypicalInitialModelState();
+    initial_state->stream_data.clear_next_page_token();
+    response_translator_.InjectResponse(std::move(initial_state));
+  }
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+  WaitForIdleTaskQueue();
+
+  // LoadMore fails, and does not make an additional request.
+  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+  EXPECT_EQ(base::nullopt, metrics_reporter_->load_more_surface_id)
+      << "metrics reporter was informed about a load more operation which "
+         "didn't begin";
+}
+
+TEST_F(FeedApiTest, LoadMoreFail) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  // Don't inject another response, which results in a proto translation
+  // failure.
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
+  EXPECT_EQ("2 slices +spinner -> 2 slices", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, LoadMoreWithClearAllInResponse) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+
+  // Use a different initial state (which includes a CLEAR_ALL).
+  response_translator_.InjectResponse(MakeTypicalInitialModelState(5));
+  CallbackReceiver<bool> callback;
+  stream_->LoadMore(surface, callback.Bind());
+
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
+
+  // Verify stored state is equivalent to in-memory model.
+  EXPECT_STRINGS_EQUAL(
+      stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(),
+      ModelStateFor(kForYouStream, store_.get()));
+
+  // Verify the new state has been pushed to |surface|.
+  ASSERT_EQ("2 slices +spinner -> 2 slices", surface.DescribeUpdates());
+
+  const feedui::StreamUpdate& initial_state = surface.update.value();
+  ASSERT_EQ(2, initial_state.updated_slices().size());
+  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
+  EXPECT_EQ("f:5", initial_state.updated_slices(0)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
+  EXPECT_EQ("f:6", initial_state.updated_slices(1)
+                       .slice()
+                       .xsurface_slice()
+                       .xsurface_frame());
+}
+
+TEST_F(FeedApiTest, LoadMoreBeforeLoad) {
+  CallbackReceiver<bool> callback;
+  TestForYouSurface surface;
+  stream_->LoadMore(surface, callback.Bind());
+
+  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
+}
+
+TEST_F(FeedApiTest, ReadNetworkResponse) {
+  base::HistogramTester histograms;
+  network_.InjectRealFeedQueryResponse();
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 10 slices", surface.DescribeUpdates());
+
+  // Verify we're processing some of the data on the request.
+
+  // The response has a privacy_notice_fulfilled=true.
+  histograms.ExpectUniqueSample(
+      "ContentSuggestions.Feed.ActivityLoggingEnabled", 1, 1);
+
+  // A request schedule with two entries was in the response. The first entry
+  // should have already been scheduled/consumed, leaving only the second
+  // entry still in the the refresh_offsets vector.
+  RequestSchedule schedule = prefs::GetRequestSchedule(
+      RefreshTaskId::kRefreshForYouFeed, profile_prefs_);
+  EXPECT_EQ(std::vector<base::TimeDelta>({
+                base::TimeDelta::FromSeconds(86308) +
+                    base::TimeDelta::FromNanoseconds(822963644),
+                base::TimeDelta::FromSeconds(120000),
+            }),
+            schedule.refresh_offsets);
+
+  // The stream's user attributes are set, so activity logging is enabled.
+  EXPECT_TRUE(stream_->IsActivityLoggingEnabled());
+  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
+}
+
+TEST_F(FeedApiTest, ClearAllAfterLoadResultsInRefresh) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->OnCacheDataCleared();  // triggers ClearAll().
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ("loading -> 2 slices -> loading -> 2 slices",
+            surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, ClearAllWithNoSurfacesAttachedDoesNotReload) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  surface.Detach();
+
+  stream_->OnCacheDataCleared();  // triggers ClearAll().
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, ClearAllWhileLoadingMore) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->LoadMore(surface, base::DoNothing());
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  stream_->OnCacheDataCleared();  // triggers ClearAll().
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(
+      "loading -> 2 slices -> 2 slices +spinner -> 4 slices -> loading -> 2 "
+      "slices",
+      surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, ClearAllWipesAllState) {
+  // Trigger saving a consistency token, so it can be cleared later.
+  network_.consistency_token = "token-11";
+  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
+  // Trigger saving a feed stream, so it can be cleared later.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Enqueue an action, so it can be cleared later.
+  stream_->UploadAction(MakeFeedAction(43ul), false, base::DoNothing());
+
+  // Trigger ClearAll, this should erase everything.
+  stream_->OnCacheDataCleared();
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 2 slices -> loading -> cant-refresh",
+            surface.DescribeUpdates());
+
+  EXPECT_EQ("{\n}\n\n", DumpStoreState());
+  EXPECT_EQ("", stream_->GetMetadata().consistency_token());
+  EXPECT_FALSE(stream_->IsActivityLoggingEnabled());
+}
+
+TEST_F(FeedApiTest, StorePendingAction) {
+  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  std::vector<feedstore::StoredAction> result =
+      ReadStoredActions(stream_->GetStore());
+  ASSERT_EQ(1ul, result.size());
+
+  EXPECT_EQ(ToTextProto(MakeFeedAction(42ul).action_payload()),
+            ToTextProto(result[0].action().action_payload()));
+}
+
+TEST_F(FeedApiTest, UploadActionWhileSignedOutIsNoOp) {
+  is_signed_in_ = false;
+  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
+}
+
+TEST_F(FeedApiTest, SignOutWhileUploadActionDoesNotUpload) {
+  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
+  is_signed_in_ = false;
+
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(UploadActionsStatus::kAbortUploadForSignedOutUser,
+            metrics_reporter_->upload_action_status);
+  EXPECT_EQ(0, network_.GetActionRequestCount());
+}
+
+TEST_F(FeedApiTest, StorePendingActionAndUploadNow) {
+  network_.consistency_token = "token-11";
+
+  // Call |ProcessThereAndBackAgain()|, which triggers Upload() with
+  // upload_now=true.
+  {
+    feedwire::ThereAndBackAgainData msg;
+    *msg.mutable_action_payload() = MakeFeedAction(42ul).action_payload();
+    stream_->ProcessThereAndBackAgain(msg.SerializeAsString());
+  }
+  WaitForIdleTaskQueue();
+
+  // Verify the action was uploaded.
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+  std::vector<feedstore::StoredAction> result =
+      ReadStoredActions(stream_->GetStore());
+  ASSERT_EQ(0ul, result.size());
+}
+
+TEST_F(FeedApiTest, ProcessViewActionResultsInDelayedUpload) {
+  network_.consistency_token = "token-11";
+
+  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+  // Verify it's not uploaded immediately.
+  ASSERT_EQ(0, network_.GetActionRequestCount());
+
+  // Trigger a network refresh.
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  // Verify the action was uploaded.
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+}
+
+TEST_F(FeedApiTest, ActionsUploadWithoutConditionsWhenFeatureDisabled) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  stream_->ProcessViewAction(
+      feedwire::FeedAction::default_instance().SerializeAsString());
+  WaitForIdleTaskQueue();
+  stream_->ProcessThereAndBackAgain(
+      MakeThereAndBackAgainData(42ul).SerializeAsString());
+  WaitForIdleTaskQueue();
+
+  // Verify the actions were uploaded.
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedApiTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
+  base::HistogramTester histograms;
+
+  // Trigger a stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(false);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+    WaitForIdleTaskQueue();
+  }
+
+  UnloadModel(kForYouStream);
+
+  // Trigger another stream refresh that updates the histogram.
+  {
+    auto model_state = MakeTypicalInitialModelState();
+    model_state->stream_data.set_privacy_notice_fulfilled(true);
+    response_translator_.InjectResponse(std::move(model_state));
+
+    refresh_scheduler_.Clear();
+    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
+    WaitForIdleTaskQueue();
+  }
+
+  // Verify that the notice card fulfillment histogram was properly recorded.
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               0, 1);
+  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
+                               1, 1);
+}
+
+TEST_F(FeedApiTest, LoadStreamFromNetworkUploadsActions) {
+  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+
+  // Uploaded action should have been erased from store.
+  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(2, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedApiTest, UploadedActionsHaveSequentialNumbers) {
+  // Send 3 actions.
+  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
+  stream_->UploadAction(MakeFeedAction(3ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+  feedwire::UploadActionsRequest request1 = *network_.GetActionRequestSent();
+
+  // Send another action in a new request.
+  stream_->UploadAction(MakeFeedAction(4ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(2, network_.GetActionRequestCount());
+  feedwire::UploadActionsRequest request2 = *network_.GetActionRequestSent();
+
+  // Verify that sent actions have sequential numbers.
+  ASSERT_EQ(3, request1.feed_actions_size());
+  ASSERT_EQ(1, request2.feed_actions_size());
+
+  EXPECT_EQ(1, request1.feed_actions(0).client_data().sequence_number());
+  EXPECT_EQ(2, request1.feed_actions(1).client_data().sequence_number());
+  EXPECT_EQ(3, request1.feed_actions(2).client_data().sequence_number());
+  EXPECT_EQ(4, request2.feed_actions(0).client_data().sequence_number());
+}
+
+TEST_F(FeedApiTest, LoadMoreUploadsActions) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  network_.consistency_token = "token-12";
+
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+  EXPECT_EQ("token-12", stream_->GetMetadata().consistency_token());
+
+  // Uploaded action should have been erased from the store.
+  network_.ClearTestData();
+  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+
+  EXPECT_EQ(
+      ToTextProto(MakeFeedAction(100ul).action_payload()),
+      ToTextProto(
+          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
+}
+
+TEST_F(FeedApiTest, LoadMoreUpdatesIsActivityLoggingEnabled) {
+  EXPECT_FALSE(stream_->IsActivityLoggingEnabled());
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->IsActivityLoggingEnabled());
+
+  int page = 2;
+  for (bool signed_in : {true, false}) {
+    for (bool waa_on : {true, false}) {
+      for (bool privacy_notice_fulfilled : {true, false}) {
+        response_translator_.InjectResponse(
+            MakeTypicalNextPageState(page++, kTestTimeEpoch, signed_in, waa_on,
+                                     privacy_notice_fulfilled));
+        CallbackReceiver<bool> callback;
+        stream_->LoadMore(surface, callback.Bind());
+        WaitForIdleTaskQueue();
+        EXPECT_EQ(
+            stream_->IsActivityLoggingEnabled(),
+            (signed_in && waa_on) ||
+                (!signed_in && GetFeedConfig().send_signed_out_session_logs))
+            << "signed_in=" << signed_in << " waa_on=" << waa_on
+            << " privacy_notice_fulfilled=" << privacy_notice_fulfilled
+            << " send_signed_out_session_logs="
+            << GetFeedConfig().send_signed_out_session_logs;
+      }
+    }
+  }
+}
+
+TEST_F(FeedApiTest, BackgroundingAppUploadsActions) {
+  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+  EXPECT_EQ(
+      ToTextProto(MakeFeedAction(1ul).action_payload()),
+      ToTextProto(
+          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
+}
+
+TEST_F(FeedApiTest, BackgroundingAppDoesNotUploadActions) {
+  Config config;
+  config.upload_actions_on_enter_background = false;
+  SetFeedConfigForTesting(config);
+
+  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(0, network_.GetActionRequestCount());
+}
+
+TEST_F(FeedApiTest, UploadedActionsAreNotSentAgain) {
+  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.GetActionRequestCount());
+
+  stream_->OnEnterBackground();
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+}
+
+TEST_F(FeedApiTest, UploadActionsOneBatch) {
+  UploadActions(
+      {MakeFeedAction(97ul), MakeFeedAction(98ul), MakeFeedAction(99ul)});
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
+
+  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(2, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedApiTest, UploadActionsMultipleBatches) {
+  UploadActions({
+      // Batch 1: One really big action.
+      MakeFeedAction(100ul, /*pad_size=*/20001ul),
+
+      // Batch 2
+      MakeFeedAction(101ul, 10000ul),
+      MakeFeedAction(102ul, 9000ul),
+
+      // Batch 3. Trigger upload.
+      MakeFeedAction(103ul, 2000ul),
+  });
+  WaitForIdleTaskQueue();
+
+  EXPECT_EQ(3, network_.GetActionRequestCount());
+
+  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
+  WaitForIdleTaskQueue();
+  EXPECT_EQ(4, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+}
+
+TEST_F(FeedApiTest, UploadActionsSkipsStaleActionsByTimestamp) {
+  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
+  WaitForIdleTaskQueue();
+  task_environment_.FastForwardBy(base::TimeDelta::FromHours(25));
+
+  // Trigger upload
+  CallbackReceiver<UploadActionsTask::Result> cr;
+  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+  WaitForIdleTaskQueue();
+
+  // Just one action should have been uploaded.
+  EXPECT_EQ(1, network_.GetActionRequestCount());
+  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
+  EXPECT_EQ(
+      ToTextProto(MakeFeedAction(3ul).action_payload()),
+      ToTextProto(
+          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
+
+  ASSERT_TRUE(cr.GetResult());
+  EXPECT_EQ(1ul, cr.GetResult()->upload_attempt_count);
+  EXPECT_EQ(1ul, cr.GetResult()->stale_count);
+}
+
+TEST_F(FeedApiTest, UploadActionsErasesStaleActionsByAttempts) {
+  // Three failed uploads, plus one more to cause the first action to be erased.
+  network_.InjectEmptyActionRequestResult();
+  stream_->UploadAction(MakeFeedAction(0ul), true, base::DoNothing());
+  network_.InjectEmptyActionRequestResult();
+  stream_->UploadAction(MakeFeedAction(1ul), true, base::DoNothing());
+  network_.InjectEmptyActionRequestResult();
+  stream_->UploadAction(MakeFeedAction(2ul), true, base::DoNothing());
+
+  CallbackReceiver<UploadActionsTask::Result> cr;
+  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
+  WaitForIdleTaskQueue();
+
+  // Four requests, three pending actions in the last request.
+  EXPECT_EQ(4, network_.GetActionRequestCount());
+  EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
+
+  // Action 0 should have been erased.
+  ASSERT_TRUE(cr.GetResult());
+  EXPECT_EQ(3ul, cr.GetResult()->upload_attempt_count);
+  EXPECT_EQ(1ul, cr.GetResult()->stale_count);
+}
+
+TEST_F(FeedApiTest, MetadataLoadedWhenDatabaseInitialized) {
+  const auto kExpiry = kTestTimeEpoch + base::TimeDelta::FromDays(1234);
+  {
+    // Write some metadata so it can be loaded when FeedStream starts up.
+    feedstore::Metadata initial_metadata;
+    feedstore::SetSessionId(initial_metadata, "session-id", kExpiry);
+    initial_metadata.set_consistency_token("token");
+    store_->WriteMetadata(initial_metadata, base::DoNothing());
+  }
+
+  // Creating a stream should load metadata.
+  CreateStream();
+
+  EXPECT_EQ("session-id", stream_->GetMetadata().session_id().token());
+  EXPECT_TIME_EQ(kExpiry,
+                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
+  EXPECT_EQ("token", stream_->GetMetadata().consistency_token());
+  // Verify the schema has been updated to the current version.
+  EXPECT_EQ((int)FeedStore::kCurrentStreamSchemaVersion,
+            stream_->GetMetadata().stream_schema_version());
+}
+
+TEST_F(FeedApiTest, ModelUnloadsAfterTimeout) {
+  Config config;
+  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
+  SetFeedConfigForTesting(config);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  surface.Detach();
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
+  WaitForIdleTaskQueue();
+  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
+}
+
+TEST_F(FeedApiTest, ModelDoesNotUnloadIfSurfaceIsAttached) {
+  Config config;
+  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
+  SetFeedConfigForTesting(config);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  surface.Detach();
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
+
+  surface.Attach(stream_.get());
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
+}
+
+TEST_F(FeedApiTest, ModelUnloadsAfterSecondTimeout) {
+  Config config;
+  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
+  SetFeedConfigForTesting(config);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  surface.Detach();
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
+
+  // Attaching another surface will prolong the unload time for another second.
+  surface.Attach(stream_.get());
+  surface.Detach();
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
+  WaitForIdleTaskQueue();
+  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
+  WaitForIdleTaskQueue();
+  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
+}
+
+TEST_F(FeedApiTest, SendsClientInstanceId) {
+  // Store is empty, so we should fallback to a network request.
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(1, network_.send_query_call_count);
+  ASSERT_TRUE(network_.query_request_sent);
+
+  // Instance ID is a random token. Verify it is not empty.
+  std::string first_instance_id = network_.query_request_sent->feed_request()
+                                      .client_info()
+                                      .client_instance_id();
+  EXPECT_NE("", first_instance_id);
+
+  // No signed-out session id was in the request.
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .chrome_client_info()
+                  .session_id()
+                  .empty());
+
+  // LoadMore, and verify the same token is used.
+  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ(2, network_.send_query_call_count);
+  EXPECT_EQ(first_instance_id, network_.query_request_sent->feed_request()
+                                   .client_info()
+                                   .client_instance_id());
+
+  // No signed-out session id was in the request.
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .chrome_client_info()
+                  .session_id()
+                  .empty());
+
+  // Trigger a ClearAll to verify the instance ID changes.
+  stream_->OnSignedOut();
+  WaitForIdleTaskQueue();
+
+  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
+  const bool is_for_next_page = false;  // No model so no first page yet.
+  const std::string new_instance_id =
+      stream_->GetRequestMetadata(kForYouStream, is_for_next_page)
+          .client_instance_id;
+  ASSERT_NE("", new_instance_id);
+  ASSERT_NE(first_instance_id, new_instance_id);
+}
+
+TEST_F(FeedApiTest, SignedOutSessionIdConsistency) {
+  const std::string kSessionToken1("session-token-1");
+  const std::string kSessionToken2("session-token-2");
+
+  is_signed_in_ = false;
+
+  StreamModelUpdateRequestGenerator model_generator;
+  model_generator.signed_in = false;
+
+  // (1) Do an initial load of the store
+  //     - this should trigger a network request
+  //     - the request should not include client-instance-id
+  //     - the request should not include a session-id
+  //     - the stream should capture the session-id token from the response
+  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+                                      kSessionToken1);
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .client_instance_id()
+                  .empty());
+  EXPECT_FALSE(network_.query_request_sent->feed_request()
+                   .client_info()
+                   .has_chrome_client_info());
+  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
+  const base::Time kSessionToken1ExpiryTime =
+      feedstore::GetSessionIdExpiryTime(stream_->GetMetadata());
+
+  // (2) LoadMore: the server returns the same session-id token
+  //     - this should trigger a network request
+  //     - the request should not include client-instance-id
+  //     - the request should include the first session-id
+  //     - the stream should retain the first session-id
+  //     - the session-id's expiry time should be unchanged
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  response_translator_.InjectResponse(model_generator.MakeNextPage(2),
+                                      kSessionToken1);
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(2, network_.send_query_call_count);
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .client_instance_id()
+                  .empty());
+  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+                                .client_info()
+                                .chrome_client_info()
+                                .session_id());
+  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
+  EXPECT_TIME_EQ(kSessionToken1ExpiryTime,
+                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
+
+  // (3) LoadMore: the server omits returning a session-id token
+  //     - this should trigger a network request
+  //     - the request should not include client-instance-id
+  //     - the request should include the first session-id
+  //     - the stream should retain the first session-id
+  //     - the session-id's expiry time should be unchanged
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  response_translator_.InjectResponse(model_generator.MakeNextPage(3));
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(3, network_.send_query_call_count);
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .client_instance_id()
+                  .empty());
+  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+                                .client_info()
+                                .chrome_client_info()
+                                .session_id());
+  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
+  EXPECT_TIME_EQ(kSessionToken1ExpiryTime,
+                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
+
+  // (4) LoadMore: the server returns new session id.
+  //     - this should trigger a network request
+  //     - the request should not include client-instance-id
+  //     - the request should include the first session-id
+  //     - the stream should retain the second session-id
+  //     - the new session-id's expiry time should be updated
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  response_translator_.InjectResponse(model_generator.MakeNextPage(4),
+                                      kSessionToken2);
+  stream_->LoadMore(surface, base::DoNothing());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(4, network_.send_query_call_count);
+  EXPECT_TRUE(network_.query_request_sent->feed_request()
+                  .client_info()
+                  .client_instance_id()
+                  .empty());
+  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+                                .client_info()
+                                .chrome_client_info()
+                                .session_id());
+  EXPECT_EQ(kSessionToken2, stream_->GetMetadata().session_id().token());
+  EXPECT_TIME_EQ(kSessionToken1ExpiryTime + base::TimeDelta::FromSeconds(3),
+                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
+}
+
+TEST_F(FeedApiTest, ClearAllResetsSessionId) {
+  is_signed_in_ = false;
+
+  // Initialize a session id.
+  feedstore::Metadata metadata = stream_->GetMetadata();
+  metadata = *feedstore::MaybeUpdateSessionId(metadata, "session-id");
+  stream_->SetMetadata(metadata);
+
+  // Trigger a ClearAll.
+  stream_->OnCacheDataCleared();
+  WaitForIdleTaskQueue();
+
+  // Session-ID should be wiped.
+  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
+  EXPECT_TRUE(
+      feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()).is_null());
+}
+
+TEST_F(FeedApiTest, SignedOutSessionIdExpiry) {
+  const std::string kSessionToken1("session-token-1");
+  const std::string kSessionToken2("session-token-2");
+
+  is_signed_in_ = false;
+
+  StreamModelUpdateRequestGenerator model_generator;
+  model_generator.signed_in = false;
+
+  // (1) Do an initial load of the store
+  //     - this should trigger a network request
+  //     - the request should not include a session-id
+  //     - the stream should capture the session-id token from the response
+  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+                                      kSessionToken1);
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_FALSE(network_.query_request_sent->feed_request()
+                   .client_info()
+                   .has_chrome_client_info());
+  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
+
+  // (2) Reload the stream from the network:
+  //     - Detach the surface, advance the clock beyond the stale content
+  //       threshold, re-attach the surface.
+  //     - this should trigger a network request
+  //     - the request should include kSessionToken1
+  //     - the stream should retain the original session-id
+  surface.Detach();
+  task_environment_.FastForwardBy(GetFeedConfig().stale_content_threshold +
+                                  base::TimeDelta::FromSeconds(1));
+  response_translator_.InjectResponse(model_generator.MakeFirstPage());
+  surface.Attach(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(2, network_.send_query_call_count);
+  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
+                                .client_info()
+                                .chrome_client_info()
+                                .session_id());
+  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
+
+  // (3) Reload the stream from the network:
+  //     - Detach the surface, advance the clock beyond the session id max age
+  //       threshold, re-attach the surface.
+  //     - this should trigger a network request
+  //     - the request should not include a session-id
+  //     - the stream should get a new session-id
+  surface.Detach();
+  task_environment_.FastForwardBy(GetFeedConfig().session_id_max_age -
+                                  GetFeedConfig().stale_content_threshold);
+  ASSERT_LT(feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()),
+            base::Time::Now());
+  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+                                      kSessionToken2);
+  surface.Attach(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(3, network_.send_query_call_count);
+  EXPECT_FALSE(network_.query_request_sent->feed_request()
+                   .client_info()
+                   .has_chrome_client_info());
+  EXPECT_EQ(kSessionToken2, stream_->GetMetadata().session_id().token());
+}
+
+TEST_F(FeedApiTest, SessionIdPersistsAcrossStreamLoads) {
+  const std::string kSessionToken("session-token-ftw");
+  const base::Time kExpiryTime =
+      kTestTimeEpoch + GetFeedConfig().session_id_max_age;
+
+  StreamModelUpdateRequestGenerator model_generator;
+  model_generator.signed_in = false;
+  is_signed_in_ = false;
+
+  // (1) Do an initial load of the store
+  //     - this should trigger a network request
+  //     - the stream should capture the session-id token from the response
+  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
+                                      kSessionToken);
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);
+
+  // (2) Reload the metadata from disk.
+  //     - the network query call count should be unchanged
+  //     - the session token and expiry time should have been reloaded.
+  surface.Detach();
+  CreateStream();
+  WaitForIdleTaskQueue();
+  ASSERT_EQ(1, network_.send_query_call_count);
+  EXPECT_EQ(kSessionToken, stream_->GetMetadata().session_id().token());
+  EXPECT_TIME_EQ(kExpiryTime,
+                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
+}
+
+TEST_F(FeedApiTest, PersistentKeyValueStoreIsClearedOnClearAll) {
+  // Store some data and verify it exists.
+  PersistentKeyValueStore* store = stream_->GetPersistentKeyValueStore();
+  store->Put("x", "y", base::DoNothing());
+  CallbackReceiver<PersistentKeyValueStore::Result> get_result;
+  store->Get("x", get_result.Bind());
+  ASSERT_EQ("y", *get_result.RunAndGetResult().get_result);
+
+  stream_->OnCacheDataCleared();  // triggers ClearAll().
+  WaitForIdleTaskQueue();
+
+  // Verify ClearAll() deleted the data.
+  get_result.Clear();
+  store->Get("x", get_result.Bind());
+  EXPECT_FALSE(get_result.RunAndGetResult().get_result);
+}
+
+TEST_F(FeedApiTest, LoadMultipleStreams) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface for_you_surface(stream_.get());
+  TestWebFeedSurface web_feed_surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 2 slices", for_you_surface.DescribeUpdates());
+  ASSERT_EQ("loading -> 2 slices", web_feed_surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, UnloadOnlyOneOfMultipleModels) {
+  Config config;
+  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
+  SetFeedConfigForTesting(config);
+
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface for_you_surface(stream_.get());
+  TestWebFeedSurface web_feed_surface(stream_.get());
+
+  WaitForIdleTaskQueue();
+
+  for_you_surface.Detach();
+
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+  WaitForIdleTaskQueue();
+
+  EXPECT_TRUE(stream_->GetModel(kWebFeedStream));
+  EXPECT_FALSE(stream_->GetModel(kForYouStream));
+}
+
+TEST_F(FeedApiTest, ExperimentsAreClearedOnClearAll) {
+  Experiments e;
+  e["Trial1"] = "Group1";
+  e["Trial2"] = "Group2";
+  prefs::SetExperiments(e, profile_prefs_);
+
+  stream_->OnCacheDataCleared();  // triggers ClearAll().
+  WaitForIdleTaskQueue();
+
+  Experiments empty;
+  Experiments got = prefs::GetExperiments(profile_prefs_);
+  EXPECT_EQ(got, empty);
+}
+
+TEST_F(FeedApiTest, CreateAndCommitEphemeralChange) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EphemeralChangeId change_id = stream_->CreateEphemeralChange(
+      surface.GetStreamType(), {MakeOperation(MakeClearAll())});
+  stream_->CommitEphemeralChange(surface.GetStreamType(), change_id);
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 2 slices -> no-cards -> no-cards",
+            surface.DescribeUpdates());
+}
+
+TEST_F(FeedApiTest, RejectEphemeralChange) {
+  response_translator_.InjectResponse(MakeTypicalInitialModelState());
+  TestForYouSurface surface(stream_.get());
+  WaitForIdleTaskQueue();
+
+  EphemeralChangeId change_id = stream_->CreateEphemeralChange(
+      surface.GetStreamType(), {MakeOperation(MakeClearAll())});
+  stream_->RejectEphemeralChange(surface.GetStreamType(), change_id);
+  WaitForIdleTaskQueue();
+
+  ASSERT_EQ("loading -> 2 slices -> no-cards -> 2 slices",
+            surface.DescribeUpdates());
+}
+
+// Keep instantiations at the bottom.
+INSTANTIATE_TEST_SUITE_P(FeedApiTest,
+                         FeedStreamTestForAllStreamTypes,
+                         ::testing::Values(kForYouStream, kWebFeedStream),
+                         ::testing::PrintToStringParamName());
+
+}  // namespace
+}  // namespace test
+}  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_test.cc b/components/feed/core/v2/api_test/feed_api_test.cc
new file mode 100644
index 0000000..4e78ecb
--- /dev/null
+++ b/components/feed/core/v2/api_test/feed_api_test.cc
@@ -0,0 +1,627 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feed/core/v2/api_test/feed_api_test.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/test/bind.h"
+#include "components/feed/core/common/pref_names.h"
+#include "components/feed/core/proto/v2/keyvalue_store.pb.h"
+#include "components/feed/core/proto/v2/store.pb.h"
+#include "components/feed/core/proto/v2/ui.pb.h"
+#include "components/feed/core/proto/v2/wire/chrome_client_info.pb.h"
+#include "components/feed/core/proto/v2/wire/request.pb.h"
+#include "components/feed/core/proto/v2/wire/there_and_back_again_data.pb.h"
+#include "components/feed/core/proto/v2/xsurface.pb.h"
+#include "components/feed/core/shared_prefs/pref_names.h"
+#include "components/feed/core/v2/config.h"
+#include "components/feed/core/v2/prefs.h"
+#include "components/feed/core/v2/test/callback_receiver.h"
+#include "components/feed/core/v2/test/proto_printer.h"
+#include "components/feed/core/v2/test/stream_builder.h"
+#include "components/feed/feed_feature_list.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "components/offline_pages/core/client_namespace_constants.h"
+
+namespace feed {
+namespace test {
+
+std::unique_ptr<StreamModel> LoadModelFromStore(const StreamType& stream_type,
+                                                FeedStore* store) {
+  LoadStreamFromStoreTask::Result result;
+  auto complete = [&](LoadStreamFromStoreTask::Result task_result) {
+    result = std::move(task_result);
+  };
+  LoadStreamFromStoreTask load_task(
+      LoadStreamFromStoreTask::LoadType::kFullLoad, stream_type, store,
+      /*missed_last_refresh=*/false, base::BindLambdaForTesting(complete));
+  // We want to load the data no matter how stale.
+  load_task.IgnoreStalenessForTesting();
+
+  base::RunLoop run_loop;
+  load_task.Execute(run_loop.QuitClosure());
+  run_loop.Run();
+
+  if (result.status == LoadStreamStatus::kLoadedFromStore) {
+    auto model = std::make_unique<StreamModel>();
+    model->Update(std::move(result.update_request));
+    return model;
+  }
+  LOG(WARNING) << "LoadModelFromStore failed with " << result.status;
+  return nullptr;
+}
+
+std::string ModelStateFor(
+    std::unique_ptr<StreamModelUpdateRequest> update_request,
+    std::vector<feedstore::DataOperation> operations,
+    std::vector<feedstore::DataOperation> more_operations) {
+  StreamModel model;
+  model.Update(std::move(update_request));
+  model.ExecuteOperations(operations);
+  model.ExecuteOperations(more_operations);
+  return model.DumpStateForTesting();
+}
+
+std::string ModelStateFor(const StreamType& stream_type, FeedStore* store) {
+  auto model = LoadModelFromStore(stream_type, store);
+  if (model) {
+    return model->DumpStateForTesting();
+  }
+  return "{Failed to load model from store}";
+}
+
+feedwire::FeedAction MakeFeedAction(int64_t id, size_t pad_size) {
+  feedwire::FeedAction action;
+
+  std::string pad;
+  if (pad_size > 0) {
+    pad = " " + std::string(pad_size - 1, 'a');
+  }
+
+  action.mutable_action_payload()->set_action_payload_data(
+      base::StrCat({base::NumberToString(id), pad}));
+  return action;
+}
+
+std::vector<feedstore::StoredAction> ReadStoredActions(FeedStore* store) {
+  base::RunLoop run_loop;
+  CallbackReceiver<std::vector<feedstore::StoredAction>> cr(&run_loop);
+  store->ReadActions(cr.Bind());
+  run_loop.Run();
+  CHECK(cr.GetResult());
+  return std::move(*cr.GetResult());
+}
+
+std::string SerializedOfflineBadgeContent() {
+  feedxsurface::OfflineBadgeContent testbadge;
+  std::string badge_serialized;
+  testbadge.set_available_offline(true);
+  testbadge.SerializeToString(&badge_serialized);
+  return badge_serialized;
+}
+
+feedwire::ThereAndBackAgainData MakeThereAndBackAgainData(int64_t id) {
+  feedwire::ThereAndBackAgainData msg;
+  *msg.mutable_action_payload() = MakeFeedAction(id).action_payload();
+  return msg;
+}
+
+TestUnreadContentObserver::TestUnreadContentObserver() = default;
+TestUnreadContentObserver::~TestUnreadContentObserver() = default;
+void TestUnreadContentObserver::HasUnreadContentChanged(
+    bool has_unread_content) {
+  calls.push_back(has_unread_content);
+}
+
+TestSurfaceBase::TestSurfaceBase(const StreamType& stream_type,
+                                 FeedStream* stream)
+    : FeedStreamSurface(stream_type) {
+  if (stream)
+    Attach(stream);
+}
+
+TestSurfaceBase::~TestSurfaceBase() {
+  if (stream_)
+    Detach();
+}
+
+void TestSurfaceBase::Attach(FeedStream* stream) {
+  EXPECT_FALSE(stream_);
+  stream_ = stream->GetWeakPtr();
+  stream_->AttachSurface(this);
+}
+
+void TestSurfaceBase::Detach() {
+  EXPECT_TRUE(stream_);
+  stream_->DetachSurface(this);
+  stream_ = nullptr;
+}
+
+void TestSurfaceBase::StreamUpdate(const feedui::StreamUpdate& stream_update) {
+  DVLOG(1) << "StreamUpdate: " << stream_update;
+  // Some special-case treatment for the loading spinner. We don't count it
+  // toward |initial_state|.
+  bool is_initial_loading_spinner = IsInitialLoadSpinnerUpdate(stream_update);
+  if (!initial_state && !is_initial_loading_spinner) {
+    initial_state = stream_update;
+  }
+  update = stream_update;
+
+  described_updates_.push_back(CurrentState());
+}
+void TestSurfaceBase::ReplaceDataStoreEntry(base::StringPiece key,
+                                            base::StringPiece data) {
+  data_store_entries_[key.as_string()] = data.as_string();
+}
+void TestSurfaceBase::RemoveDataStoreEntry(base::StringPiece key) {
+  data_store_entries_.erase(key.as_string());
+}
+
+void TestSurfaceBase::Clear() {
+  initial_state = base::nullopt;
+  update = base::nullopt;
+  described_updates_.clear();
+}
+
+std::string TestSurfaceBase::DescribeUpdates() {
+  std::string result = base::JoinString(described_updates_, " -> ");
+  described_updates_.clear();
+  return result;
+}
+
+std::map<std::string, std::string> TestSurfaceBase::GetDataStoreEntries()
+    const {
+  return data_store_entries_;
+}
+std::string TestSurfaceBase::CurrentState() {
+  if (update && IsInitialLoadSpinnerUpdate(*update))
+    return "loading";
+
+  if (!initial_state)
+    return "empty";
+
+  bool has_loading_spinner = false;
+  for (int i = 0; i < update->updated_slices().size(); ++i) {
+    const feedui::StreamUpdate_SliceUpdate& slice_update =
+        update->updated_slices(i);
+    if (slice_update.has_slice() &&
+        slice_update.slice().has_zero_state_slice()) {
+      CHECK(update->updated_slices().size() == 1)
+          << "Zero state with other slices" << *update;
+      // Returns either "no-cards" or "cant-refresh".
+      return update->updated_slices()[0].slice().slice_id();
+    }
+    if (slice_update.has_slice() &&
+        slice_update.slice().has_loading_spinner_slice()) {
+      CHECK_EQ(i, update->updated_slices().size() - 1)
+          << "Loading spinner in an unexpected place" << *update;
+      has_loading_spinner = true;
+    }
+  }
+  std::stringstream ss;
+  if (has_loading_spinner) {
+    ss << update->updated_slices().size() - 1 << " slices +spinner";
+  } else {
+    ss << update->updated_slices().size() << " slices";
+  }
+  return ss.str();
+}
+
+bool TestSurfaceBase::IsInitialLoadSpinnerUpdate(
+    const feedui::StreamUpdate& update) {
+  return update.updated_slices().size() == 1 &&
+         update.updated_slices()[0].has_slice() &&
+         update.updated_slices()[0].slice().has_loading_spinner_slice();
+}
+
+TestForYouSurface::TestForYouSurface(FeedStream* stream)
+    : TestSurfaceBase(kForYouStream, stream) {}
+TestWebFeedSurface::TestWebFeedSurface(FeedStream* stream)
+    : TestSurfaceBase(kWebFeedStream, stream) {}
+
+TestImageFetcher::TestImageFetcher(
+    scoped_refptr<::network::SharedURLLoaderFactory> url_loader_factory)
+    : ImageFetcher(url_loader_factory) {}
+
+ImageFetchId TestImageFetcher::Fetch(
+    const GURL& url,
+    base::OnceCallback<void(NetworkResponse)> callback) {
+  // Emulate a response.
+  NetworkResponse response = {"dummyresponse", 200};
+  std::move(callback).Run(std::move(response));
+  return id_generator_.GenerateNextId();
+}
+
+TestFeedNetwork::TestFeedNetwork() = default;
+TestFeedNetwork::~TestFeedNetwork() = default;
+void TestFeedNetwork::SendQueryRequest(
+    NetworkRequestType request_type,
+    const feedwire::Request& request,
+    bool force_signed_out_request,
+    base::OnceCallback<void(QueryRequestResult)> callback) {
+  forced_signed_out_request = force_signed_out_request;
+  ++send_query_call_count;
+  // Emulate a successful response.
+  // The response body is currently an empty message, because most of the
+  // time we want to inject a translated response for ease of test-writing.
+  query_request_sent = request;
+  QueryRequestResult result;
+  result.response_info.status_code = 200;
+  result.response_info.response_body_bytes = 100;
+  result.response_info.fetch_duration = base::TimeDelta::FromMilliseconds(42);
+  result.response_info.was_signed_in = true;
+  if (injected_response_) {
+    result.response_body = std::make_unique<feedwire::Response>(
+        std::move(injected_response_.value()));
+  } else {
+    result.response_body = std::make_unique<feedwire::Response>();
+  }
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
+}
+
+void TestFeedNetwork::SendDiscoverApiRequest(
+    base::StringPiece api_path,
+    base::StringPiece method,
+    std::string request_bytes,
+    base::OnceCallback<void(RawResponse)> callback) {
+  api_requests_sent_[api_path.as_string()] = request_bytes;
+  ++api_request_count_[api_path.as_string()];
+  std::vector<RawResponse>& injected_responses =
+      injected_api_responses_[api_path.as_string()];
+
+  // If there is no injected response, create a default response.
+  if (injected_responses.empty()) {
+    if (api_path == UploadActionsDiscoverApi::RequestPath()) {
+      feedwire::UploadActionsRequest request;
+      ASSERT_TRUE(request.ParseFromString(request_bytes));
+      feedwire::UploadActionsResponse response_message;
+      response_message.mutable_consistency_token()->set_token(
+          consistency_token);
+      InjectApiResponse<UploadActionsDiscoverApi>(response_message);
+    }
+  }
+
+  if (!injected_responses.empty()) {
+    RawResponse response = injected_responses[0];
+    injected_responses.erase(injected_responses.begin());
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
+    return;
+  }
+  ASSERT_TRUE(false) << "No API response injected, and no default is available:"
+                     << api_path;
+}
+
+void TestFeedNetwork::CancelRequests() {
+  NOTIMPLEMENTED();
+}
+
+void TestFeedNetwork::InjectRealFeedQueryResponse() {
+  base::FilePath response_file_path;
+  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &response_file_path));
+  response_file_path = response_file_path.AppendASCII(
+      "components/test/data/feed/response.binarypb");
+  std::string response_data;
+  CHECK(base::ReadFileToString(response_file_path, &response_data));
+
+  feedwire::Response response;
+  CHECK(response.ParseFromString(response_data));
+
+  injected_response_ = response;
+}
+
+void TestFeedNetwork::InjectEmptyActionRequestResult() {
+  InjectApiRawResponse<UploadActionsDiscoverApi>({});
+}
+
+base::Optional<feedwire::UploadActionsRequest>
+TestFeedNetwork::GetActionRequestSent() {
+  return GetApiRequestSent<UploadActionsDiscoverApi>();
+}
+
+int TestFeedNetwork::GetActionRequestCount() const {
+  return GetApiRequestCount<UploadActionsDiscoverApi>();
+}
+
+void TestFeedNetwork::ClearTestData() {
+  injected_api_responses_.clear();
+  api_requests_sent_.clear();
+  api_request_count_.clear();
+  injected_response_.reset();
+}
+
+TestWireResponseTranslator::TestWireResponseTranslator() = default;
+TestWireResponseTranslator::~TestWireResponseTranslator() = default;
+RefreshResponseData TestWireResponseTranslator::TranslateWireResponse(
+    feedwire::Response response,
+    StreamModelUpdateRequest::Source source,
+    bool was_signed_in_request,
+    base::Time current_time) const {
+  if (!injected_responses_.empty()) {
+    if (injected_responses_[0].model_update_request)
+      injected_responses_[0].model_update_request->source = source;
+    RefreshResponseData result = std::move(injected_responses_[0]);
+    injected_responses_.erase(injected_responses_.begin());
+    return result;
+  }
+  return WireResponseTranslator::TranslateWireResponse(
+      std::move(response), source, was_signed_in_request, current_time);
+}
+void TestWireResponseTranslator::InjectResponse(
+    std::unique_ptr<StreamModelUpdateRequest> response,
+    base::Optional<std::string> session_id) {
+  DCHECK(!response->stream_data.signed_in() || !session_id);
+  RefreshResponseData data;
+  data.model_update_request = std::move(response);
+  data.session_id = std::move(session_id);
+  InjectResponse(std::move(data));
+}
+void TestWireResponseTranslator::InjectResponse(
+    RefreshResponseData response_data) {
+  injected_responses_.push_back(std::move(response_data));
+}
+bool TestWireResponseTranslator::InjectedResponseConsumed() const {
+  return injected_responses_.empty();
+}
+
+FakeRefreshTaskScheduler::FakeRefreshTaskScheduler() = default;
+FakeRefreshTaskScheduler::~FakeRefreshTaskScheduler() = default;
+void FakeRefreshTaskScheduler::EnsureScheduled(RefreshTaskId id,
+                                               base::TimeDelta run_time) {
+  scheduled_run_times[id] = run_time;
+}
+void FakeRefreshTaskScheduler::Cancel(RefreshTaskId id) {
+  canceled_tasks.insert(id);
+}
+void FakeRefreshTaskScheduler::RefreshTaskComplete(RefreshTaskId id) {
+  completed_tasks.insert(id);
+}
+
+void FakeRefreshTaskScheduler::Clear() {
+  scheduled_run_times.clear();
+  canceled_tasks.clear();
+  completed_tasks.clear();
+}
+
+TestMetricsReporter::TestMetricsReporter(PrefService* prefs)
+    : MetricsReporter(prefs) {}
+TestMetricsReporter::~TestMetricsReporter() = default;
+void TestMetricsReporter::ContentSliceViewed(const StreamType& stream_type,
+                                             int index_in_stream) {
+  slice_viewed_index = index_in_stream;
+  MetricsReporter::ContentSliceViewed(stream_type, index_in_stream);
+}
+void TestMetricsReporter::OnLoadStream(
+    LoadStreamStatus load_from_store_status,
+    LoadStreamStatus final_status,
+    bool loaded_new_content_from_network,
+    base::TimeDelta stored_content_age,
+    std::unique_ptr<LoadLatencyTimes> latencies) {
+  load_stream_from_store_status = load_from_store_status;
+  load_stream_status = final_status;
+  LOG(INFO) << "OnLoadStream: " << final_status
+            << " (store status: " << load_from_store_status << ")";
+  MetricsReporter::OnLoadStream(load_from_store_status, final_status,
+                                loaded_new_content_from_network,
+                                stored_content_age, std::move(latencies));
+}
+void TestMetricsReporter::OnLoadMoreBegin(SurfaceId surface_id) {
+  load_more_surface_id = surface_id;
+  MetricsReporter::OnLoadMoreBegin(surface_id);
+}
+void TestMetricsReporter::OnLoadMore(LoadStreamStatus final_status) {
+  load_more_status = final_status;
+  MetricsReporter::OnLoadMore(final_status);
+}
+void TestMetricsReporter::OnBackgroundRefresh(LoadStreamStatus final_status) {
+  background_refresh_status = final_status;
+  MetricsReporter::OnBackgroundRefresh(final_status);
+}
+void TestMetricsReporter::OnClearAll(base::TimeDelta time_since_last_clear) {
+  this->time_since_last_clear = time_since_last_clear;
+  MetricsReporter::OnClearAll(time_since_last_clear);
+}
+void TestMetricsReporter::OnUploadActions(UploadActionsStatus status) {
+  upload_action_status = status;
+  MetricsReporter::OnUploadActions(status);
+}
+
+TestPrefetchService::TestPrefetchService() = default;
+TestPrefetchService::~TestPrefetchService() = default;
+void TestPrefetchService::SetSuggestionProvider(
+    offline_pages::SuggestionsProvider* suggestions_provider) {
+  suggestions_provider_ = suggestions_provider;
+}
+void TestPrefetchService::NewSuggestionsAvailable() {
+  ++new_suggestions_available_call_count_;
+}
+
+offline_pages::SuggestionsProvider*
+TestPrefetchService::suggestions_provider() {
+  return suggestions_provider_;
+}
+int TestPrefetchService::NewSuggestionsAvailableCallCount() const {
+  return new_suggestions_available_call_count_;
+}
+TestOfflinePageModel::TestOfflinePageModel() = default;
+TestOfflinePageModel::~TestOfflinePageModel() = default;
+void TestOfflinePageModel::AddObserver(Observer* observer) {
+  CHECK(observers_.insert(observer).second);
+}
+void TestOfflinePageModel::RemoveObserver(Observer* observer) {
+  CHECK_EQ(1UL, observers_.erase(observer));
+}
+void TestOfflinePageModel::GetPagesWithCriteria(
+    const offline_pages::PageCriteria& criteria,
+    offline_pages::MultipleOfflinePageItemCallback callback) {
+  std::vector<offline_pages::OfflinePageItem> result;
+  for (const offline_pages::OfflinePageItem& item : items_) {
+    if (MeetsCriteria(criteria, item)) {
+      result.push_back(item);
+    }
+  }
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), result));
+}
+
+void TestOfflinePageModel::AddTestPage(const GURL& url) {
+  offline_pages::OfflinePageItem item;
+  item.url = url;
+  item.client_id =
+      offline_pages::ClientId(offline_pages::kSuggestedArticlesNamespace, "");
+  items_.push_back(item);
+}
+
+void TestOfflinePageModel::CallObserverOfflinePageAdded(
+    const offline_pages::OfflinePageItem& item) {
+  for (Observer* observer : observers_) {
+    observer->OfflinePageAdded(this, item);
+  }
+}
+
+void TestOfflinePageModel::CallObserverOfflinePageDeleted(
+    const offline_pages::OfflinePageItem& item) {
+  for (Observer* observer : observers_) {
+    observer->OfflinePageDeleted(item);
+  }
+}
+
+FeedApiTest::FeedApiTest() = default;
+FeedApiTest::~FeedApiTest() = default;
+void FeedApiTest::SetUp() {
+  SetupFeatures();
+  kTestTimeEpoch = base::Time::Now();
+
+  // Reset to default config, since tests can change it.
+  SetFeedConfigForTesting(Config());
+
+  feed::prefs::RegisterFeedSharedProfilePrefs(profile_prefs_.registry());
+  feed::RegisterProfilePrefs(profile_prefs_.registry());
+  metrics_reporter_ = std::make_unique<TestMetricsReporter>(&profile_prefs_);
+
+  shared_url_loader_factory_ =
+      base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+          &test_factory_);
+  image_fetcher_ =
+      std::make_unique<TestImageFetcher>(shared_url_loader_factory_);
+
+  CreateStream();
+}
+
+void FeedApiTest::TearDown() {
+  // Ensure the task queue can return to idle. Failure to do so may be
+  // due to a stuck task that never called |TaskComplete()|.
+  WaitForIdleTaskQueue();
+  // ProtoDatabase requires PostTask to clean up.
+  store_.reset();
+  persistent_key_value_store_.reset();
+  task_environment_.RunUntilIdle();
+}
+bool FeedApiTest::IsEulaAccepted() {
+  return is_eula_accepted_;
+}
+bool FeedApiTest::IsOffline() {
+  return is_offline_;
+}
+bool FeedApiTest::IsSignedIn() {
+  return is_signed_in_;
+}
+DisplayMetrics FeedApiTest::GetDisplayMetrics() {
+  DisplayMetrics result;
+  result.density = 200;
+  result.height_pixels = 800;
+  result.width_pixels = 350;
+  return result;
+}
+std::string FeedApiTest::GetLanguageTag() {
+  return "en-US";
+}
+void FeedApiTest::PrefetchImage(const GURL& url) {
+  prefetched_images_.push_back(url);
+  prefetch_image_call_count_++;
+}
+
+void FeedApiTest::CreateStream() {
+  ChromeInfo chrome_info;
+  chrome_info.channel = version_info::Channel::STABLE;
+  chrome_info.version = base::Version({99, 1, 9911, 2});
+  stream_ = std::make_unique<FeedStream>(
+      &refresh_scheduler_, metrics_reporter_.get(), this, &profile_prefs_,
+      &network_, image_fetcher_.get(), store_.get(),
+      persistent_key_value_store_.get(), &prefetch_service_,
+      &offline_page_model_, chrome_info);
+
+  WaitForIdleTaskQueue();  // Wait for any initialization.
+  stream_->SetWireResponseTranslatorForTesting(&response_translator_);
+}
+
+bool FeedApiTest::IsTaskQueueIdle() const {
+  return !stream_->GetTaskQueueForTesting()->HasPendingTasks() &&
+         !stream_->GetTaskQueueForTesting()->HasRunningTask();
+}
+
+void FeedApiTest::WaitForIdleTaskQueue() {
+  if (IsTaskQueueIdle())
+    return;
+  base::test::ScopedRunLoopTimeout run_timeout(FROM_HERE,
+                                               base::TimeDelta::FromSeconds(1));
+  base::RunLoop run_loop;
+  stream_->SetIdleCallbackForTesting(run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+void FeedApiTest::UnloadModel(const StreamType& stream_type) {
+  WaitForIdleTaskQueue();
+  stream_->UnloadModel(stream_type);
+}
+
+std::string FeedApiTest::DumpStoreState(bool print_keys) {
+  base::RunLoop run_loop;
+  std::unique_ptr<std::map<std::string, feedstore::Record>> records;
+  auto callback =
+      [&](bool,
+          std::unique_ptr<std::map<std::string, feedstore::Record>> result) {
+        records = std::move(result);
+        run_loop.Quit();
+      };
+  store_->GetDatabaseForTesting()->LoadKeysAndEntries(
+      base::BindLambdaForTesting(callback));
+
+  run_loop.Run();
+  std::stringstream ss;
+  for (const auto& item : *records) {
+    if (print_keys)
+      ss << '"' << item.first << "\": ";
+
+    ss << item.second << '\n';
+  }
+  return ss.str();
+}
+
+void FeedApiTest::UploadActions(std::vector<feedwire::FeedAction> actions) {
+  size_t actions_remaining = actions.size();
+  for (feedwire::FeedAction& action : actions) {
+    stream_->UploadAction(action, (--actions_remaining) == 0ul,
+                          base::DoNothing());
+  }
+}
+
+RefreshTaskId FeedStreamTestForAllStreamTypes::GetRefreshTaskId() const {
+  RefreshTaskId id;
+  CHECK(GetStreamType().GetRefreshTaskId(id));
+  return id;
+}
+
+}  // namespace test
+}  // namespace feed
diff --git a/components/feed/core/v2/api_test/feed_api_test.h b/components/feed/core/v2/api_test/feed_api_test.h
new file mode 100644
index 0000000..3334993
--- /dev/null
+++ b/components/feed/core/v2/api_test/feed_api_test.h
@@ -0,0 +1,415 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEED_CORE_V2_API_TEST_FEED_API_TEST_H_
+#define COMPONENTS_FEED_CORE_V2_API_TEST_FEED_API_TEST_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/optional.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "components/feed/core/common/pref_names.h"
+#include "components/feed/core/proto/v2/keyvalue_store.pb.h"
+#include "components/feed/core/proto/v2/wire/there_and_back_again_data.pb.h"
+#include "components/feed/core/shared_prefs/pref_names.h"
+#include "components/feed/core/v2/enums.h"
+#include "components/feed/core/v2/feed_network.h"
+#include "components/feed/core/v2/feed_store.h"
+#include "components/feed/core/v2/feed_stream.h"
+#include "components/feed/core/v2/image_fetcher.h"
+#include "components/feed/core/v2/prefs.h"
+#include "components/feed/core/v2/stream_model.h"
+#include "components/feed/core/v2/test/proto_printer.h"
+#include "components/feed/core/v2/test/stream_builder.h"
+#include "components/feed/core/v2/test/test_util.h"
+#include "components/feed/core/v2/wire_response_translator.h"
+#include "components/offline_pages/core/prefetch/stub_prefetch_service.h"
+#include "components/offline_pages/core/stub_offline_page_model.h"
+#include "components/prefs/testing_pref_service.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace feed {
+namespace test {
+
+std::unique_ptr<StreamModel> LoadModelFromStore(const StreamType& stream_type,
+                                                FeedStore* store);
+
+// Returns the model state string (|StreamModel::DumpStateForTesting()|),
+// given a model initialized with |update_request| and having |operations|
+// applied.
+std::string ModelStateFor(
+    std::unique_ptr<StreamModelUpdateRequest> update_request,
+    std::vector<feedstore::DataOperation> operations = {},
+    std::vector<feedstore::DataOperation> more_operations = {});
+
+// Returns the model state string (|StreamModel::DumpStateForTesting()|),
+// given a model initialized with |store|.
+std::string ModelStateFor(const StreamType& stream_type, FeedStore* store);
+
+feedwire::FeedAction MakeFeedAction(int64_t id, size_t pad_size = 0);
+
+std::vector<feedstore::StoredAction> ReadStoredActions(FeedStore* store);
+
+std::string SerializedOfflineBadgeContent();
+
+feedwire::ThereAndBackAgainData MakeThereAndBackAgainData(int64_t id);
+
+class TestSurfaceBase : public FeedStreamSurface {
+ public:
+  // Provide some helper functionality to attach/detach the surface.
+  // This way we can auto-detach in the destructor.
+  explicit TestSurfaceBase(const StreamType& stream_type,
+                           FeedStream* stream = nullptr);
+
+  ~TestSurfaceBase() override;
+
+  void Attach(FeedStream* stream);
+
+  void Detach();
+
+  // FeedStream::FeedStreamSurface.
+  void StreamUpdate(const feedui::StreamUpdate& stream_update) override;
+  void ReplaceDataStoreEntry(base::StringPiece key,
+                             base::StringPiece data) override;
+  void RemoveDataStoreEntry(base::StringPiece key) override;
+
+  // Test functions.
+
+  void Clear();
+
+  // Returns a description of the updates this surface received. Each update
+  // is separated by ' -> '. Returns only the updates since the last call.
+  std::string DescribeUpdates();
+
+  std::map<std::string, std::string> GetDataStoreEntries() const;
+
+  // The initial state of the stream, if it was received. This is nullopt if
+  // only the loading spinner was seen.
+  base::Optional<feedui::StreamUpdate> initial_state;
+  // The last stream update received.
+  base::Optional<feedui::StreamUpdate> update;
+
+ private:
+  std::string CurrentState();
+
+  bool IsInitialLoadSpinnerUpdate(const feedui::StreamUpdate& update);
+
+  // The stream if it was attached using the constructor.
+  base::WeakPtr<FeedStream> stream_;
+  std::vector<std::string> described_updates_;
+  std::map<std::string, std::string> data_store_entries_;
+};
+
+class TestForYouSurface : public TestSurfaceBase {
+ public:
+  explicit TestForYouSurface(FeedStream* stream = nullptr);
+};
+class TestWebFeedSurface : public TestSurfaceBase {
+ public:
+  explicit TestWebFeedSurface(FeedStream* stream = nullptr);
+};
+
+class TestImageFetcher : public ImageFetcher {
+ public:
+  explicit TestImageFetcher(
+      scoped_refptr<::network::SharedURLLoaderFactory> url_loader_factory);
+  ImageFetchId Fetch(
+      const GURL& url,
+      base::OnceCallback<void(NetworkResponse)> callback) override;
+  void Cancel(ImageFetchId id) override {}
+
+ private:
+  ImageFetchId::Generator id_generator_;
+};
+
+class TestUnreadContentObserver : public FeedApi::UnreadContentObserver {
+ public:
+  TestUnreadContentObserver();
+  ~TestUnreadContentObserver() override;
+  void HasUnreadContentChanged(bool has_unread_content) override;
+
+  std::vector<bool> calls;
+};
+
+class TestFeedNetwork : public FeedNetwork {
+ public:
+  TestFeedNetwork();
+  ~TestFeedNetwork() override;
+  // FeedNetwork implementation.
+  void SendQueryRequest(
+      NetworkRequestType request_type,
+      const feedwire::Request& request,
+      bool force_signed_out_request,
+      base::OnceCallback<void(QueryRequestResult)> callback) override;
+
+  void SendDiscoverApiRequest(
+      base::StringPiece api_path,
+      base::StringPiece method,
+      std::string request_bytes,
+      base::OnceCallback<void(RawResponse)> callback) override;
+
+  void CancelRequests() override;
+
+  void InjectRealFeedQueryResponse();
+
+  template <typename API>
+  void InjectApiRawResponse(RawResponse result) {
+    injected_api_responses_[API::RequestPath().as_string()].push_back(result);
+  }
+
+  template <typename API>
+  void InjectApiResponse(const typename API::Response& response_message) {
+    RawResponse response;
+    response.response_info.status_code = 200;
+    response.response_bytes = response_message.SerializeAsString();
+    response.response_info.response_body_bytes = response.response_bytes.size();
+    InjectApiRawResponse<API>(std::move(response));
+  }
+
+  void InjectEmptyActionRequestResult();
+
+  template <typename API>
+  base::Optional<typename API::Request> GetApiRequestSent() {
+    base::Optional<typename API::Request> result;
+    auto iter = api_requests_sent_.find(API::RequestPath().as_string());
+    if (iter != api_requests_sent_.end()) {
+      typename API::Request message;
+      if (!iter->second.empty()) {
+        if (!message.ParseFromString(iter->second)) {
+          LOG(ERROR) << "Failed to parse API request.";
+          return base::nullopt;
+        }
+      }
+      result = message;
+    }
+    return result;
+  }
+
+  base::Optional<feedwire::UploadActionsRequest> GetActionRequestSent();
+
+  template <typename API>
+  int GetApiRequestCount() const {
+    auto iter = api_request_count_.find(API::RequestPath().as_string());
+    return iter == api_request_count_.end() ? 0 : iter->second;
+  }
+  int GetActionRequestCount() const;
+  void ClearTestData();
+
+  base::Optional<feedwire::Request> query_request_sent;
+  int send_query_call_count = 0;
+  std::string consistency_token;
+  bool forced_signed_out_request = false;
+
+ private:
+  std::map<std::string, std::vector<RawResponse>> injected_api_responses_;
+  std::map<std::string, std::string> api_requests_sent_;
+  std::map<std::string, int> api_request_count_;
+  base::Optional<feedwire::Response> injected_response_;
+};
+
+// Forwards to |FeedStream::WireResponseTranslator| unless a response is
+// injected.
+class TestWireResponseTranslator : public WireResponseTranslator {
+ public:
+  TestWireResponseTranslator();
+  ~TestWireResponseTranslator();
+  RefreshResponseData TranslateWireResponse(
+      feedwire::Response response,
+      StreamModelUpdateRequest::Source source,
+      bool was_signed_in_request,
+      base::Time current_time) const override;
+  void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response,
+                      base::Optional<std::string> session_id = base::nullopt);
+  void InjectResponse(RefreshResponseData response_data);
+  bool InjectedResponseConsumed() const;
+
+ private:
+  mutable std::vector<RefreshResponseData> injected_responses_;
+};
+
+class FakeRefreshTaskScheduler : public RefreshTaskScheduler {
+ public:
+  FakeRefreshTaskScheduler();
+  ~FakeRefreshTaskScheduler() override;
+  // RefreshTaskScheduler implementation.
+  void EnsureScheduled(RefreshTaskId id, base::TimeDelta run_time) override;
+  void Cancel(RefreshTaskId id) override;
+  void RefreshTaskComplete(RefreshTaskId id) override;
+
+  void Clear();
+
+  std::map<RefreshTaskId, base::TimeDelta> scheduled_run_times;
+  std::set<RefreshTaskId> canceled_tasks;
+  std::set<RefreshTaskId> completed_tasks;
+
+ private:
+  std::stringstream activity_log_;
+};
+
+class TestMetricsReporter : public MetricsReporter {
+ public:
+  explicit TestMetricsReporter(PrefService* prefs);
+  ~TestMetricsReporter() override;
+
+  // MetricsReporter.
+  void ContentSliceViewed(const StreamType& stream_type,
+                          int index_in_stream) override;
+  void OnLoadStream(LoadStreamStatus load_from_store_status,
+                    LoadStreamStatus final_status,
+                    bool loaded_new_content_from_network,
+                    base::TimeDelta stored_content_age,
+                    std::unique_ptr<LoadLatencyTimes> latencies) override;
+  void OnLoadMoreBegin(SurfaceId surface_id) override;
+  void OnLoadMore(LoadStreamStatus final_status) override;
+  void OnBackgroundRefresh(LoadStreamStatus final_status) override;
+  void OnClearAll(base::TimeDelta time_since_last_clear) override;
+  void OnUploadActions(UploadActionsStatus status) override;
+
+  // Test access.
+
+  base::Optional<int> slice_viewed_index;
+  base::Optional<LoadStreamStatus> load_stream_status;
+  base::Optional<LoadStreamStatus> load_stream_from_store_status;
+  base::Optional<SurfaceId> load_more_surface_id;
+  base::Optional<LoadStreamStatus> load_more_status;
+  base::Optional<LoadStreamStatus> background_refresh_status;
+  base::Optional<base::TimeDelta> time_since_last_clear;
+  base::Optional<UploadActionsStatus> upload_action_status;
+};
+
+class TestPrefetchService : public offline_pages::StubPrefetchService {
+ public:
+  TestPrefetchService();
+  ~TestPrefetchService() override;
+  // offline_pages::StubPrefetchService.
+  void SetSuggestionProvider(
+      offline_pages::SuggestionsProvider* suggestions_provider) override;
+  void NewSuggestionsAvailable() override;
+
+  // Test functionality.
+  offline_pages::SuggestionsProvider* suggestions_provider();
+  int NewSuggestionsAvailableCallCount() const;
+
+ private:
+  offline_pages::SuggestionsProvider* suggestions_provider_ = nullptr;
+  int new_suggestions_available_call_count_ = 0;
+};
+
+class TestOfflinePageModel : public offline_pages::StubOfflinePageModel {
+ public:
+  TestOfflinePageModel();
+  ~TestOfflinePageModel() override;
+  // offline_pages::OfflinePageModel
+  void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
+  void GetPagesWithCriteria(
+      const offline_pages::PageCriteria& criteria,
+      offline_pages::MultipleOfflinePageItemCallback callback) override;
+
+  // Test functions.
+
+  void AddTestPage(const GURL& url);
+  std::vector<offline_pages::OfflinePageItem>& items() { return items_; }
+  void CallObserverOfflinePageAdded(const offline_pages::OfflinePageItem& item);
+  void CallObserverOfflinePageDeleted(
+      const offline_pages::OfflinePageItem& item);
+
+ private:
+  std::vector<offline_pages::OfflinePageItem> items_;
+  std::set<Observer*> observers_;
+};
+
+class FeedApiTest : public testing::Test, public FeedStream::Delegate {
+ public:
+  FeedApiTest();
+  ~FeedApiTest() override;
+  void SetUp() override;
+
+  virtual void SetupFeatures() {}
+
+  void TearDown() override;
+
+  // FeedStream::Delegate.
+  bool IsEulaAccepted() override;
+  bool IsOffline() override;
+  DisplayMetrics GetDisplayMetrics() override;
+  std::string GetLanguageTag() override;
+  void ClearAll() override {}
+  bool IsSignedIn() override;
+  void PrefetchImage(const GURL& url) override;
+  void RegisterExperiments(const Experiments& experiments) override {}
+
+  // For tests.
+
+  // Replace stream_.
+  void CreateStream();
+  bool IsTaskQueueIdle() const;
+  void WaitForIdleTaskQueue();
+  void UnloadModel(const StreamType& stream_type);
+
+  // Dumps the state of |FeedStore| to a string for debugging.
+  std::string DumpStoreState(bool print_keys = false);
+
+  void UploadActions(std::vector<feedwire::FeedAction> actions);
+
+ protected:
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+  TestingPrefServiceSimple profile_prefs_;
+  std::unique_ptr<TestMetricsReporter> metrics_reporter_;
+  TestFeedNetwork network_;
+  TestWireResponseTranslator response_translator_;
+  std::unique_ptr<TestImageFetcher> image_fetcher_;
+  network::TestURLLoaderFactory test_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
+
+  std::unique_ptr<FeedStore> store_ = std::make_unique<FeedStore>(
+      leveldb_proto::ProtoDatabaseProvider::GetUniqueDB<feedstore::Record>(
+          leveldb_proto::ProtoDbType::FEED_STREAM_DATABASE,
+          /*db_dir=*/{},
+          task_environment_.GetMainThreadTaskRunner()));
+
+  std::unique_ptr<PersistentKeyValueStoreImpl> persistent_key_value_store_ =
+      std::make_unique<PersistentKeyValueStoreImpl>(
+          leveldb_proto::ProtoDatabaseProvider::GetUniqueDB<feedkvstore::Entry>(
+              leveldb_proto::ProtoDbType::FEED_KEY_VALUE_DATABASE,
+              /*db_dir=*/{},
+              task_environment_.GetMainThreadTaskRunner()));
+
+  FakeRefreshTaskScheduler refresh_scheduler_;
+  TestPrefetchService prefetch_service_;
+  TestOfflinePageModel offline_page_model_;
+  std::unique_ptr<FeedStream> stream_;
+  bool is_eula_accepted_ = true;
+  bool is_offline_ = false;
+  bool is_signed_in_ = true;
+  base::test::ScopedFeatureList scoped_feature_list_;
+  int prefetch_image_call_count_ = 0;
+  std::vector<GURL> prefetched_images_;
+};
+
+class FeedStreamTestForAllStreamTypes
+    : public FeedApiTest,
+      public ::testing::WithParamInterface<StreamType> {
+ public:
+  static StreamType GetStreamType() { return GetParam(); }
+  class TestSurface : public TestSurfaceBase {
+   public:
+    explicit TestSurface(FeedStream* stream = nullptr)
+        : TestSurfaceBase(FeedStreamTestForAllStreamTypes::GetStreamType(),
+                          stream) {}
+  };
+  RefreshTaskId GetRefreshTaskId() const;
+};
+
+}  // namespace test
+}  // namespace feed
+
+#endif  // COMPONENTS_FEED_CORE_V2_API_TEST_FEED_API_TEST_H_
diff --git a/components/feed/core/v2/feed_stream_unittest.cc b/components/feed/core/v2/feed_stream_unittest.cc
deleted file mode 100644
index f4874df..0000000
--- a/components/feed/core/v2/feed_stream_unittest.cc
+++ /dev/null
@@ -1,3240 +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 "components/feed/core/v2/feed_stream.h"
-
-#include <map>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <string>
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/optional.h"
-#include "base/path_service.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/test/bind.h"
-#include "base/test/metrics/histogram_tester.h"
-#include "base/test/metrics/user_action_tester.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/test/scoped_run_loop_timeout.h"
-#include "base/test/task_environment.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "base/time/clock.h"
-#include "components/feed/core/common/pref_names.h"
-#include "components/feed/core/proto/v2/keyvalue_store.pb.h"
-#include "components/feed/core/proto/v2/store.pb.h"
-#include "components/feed/core/proto/v2/ui.pb.h"
-#include "components/feed/core/proto/v2/wire/chrome_client_info.pb.h"
-#include "components/feed/core/proto/v2/wire/request.pb.h"
-#include "components/feed/core/proto/v2/wire/there_and_back_again_data.pb.h"
-#include "components/feed/core/proto/v2/xsurface.pb.h"
-#include "components/feed/core/shared_prefs/pref_names.h"
-#include "components/feed/core/v2/config.h"
-#include "components/feed/core/v2/feed_network.h"
-#include "components/feed/core/v2/feedstore_util.h"
-#include "components/feed/core/v2/image_fetcher.h"
-#include "components/feed/core/v2/metrics_reporter.h"
-#include "components/feed/core/v2/persistent_key_value_store_impl.h"
-#include "components/feed/core/v2/prefs.h"
-#include "components/feed/core/v2/protocol_translator.h"
-#include "components/feed/core/v2/public/feed_api.h"
-#include "components/feed/core/v2/public/persistent_key_value_store.h"
-#include "components/feed/core/v2/public/refresh_task_scheduler.h"
-#include "components/feed/core/v2/scheduling.h"
-#include "components/feed/core/v2/stream_model.h"
-#include "components/feed/core/v2/tasks/load_stream_from_store_task.h"
-#include "components/feed/core/v2/test/callback_receiver.h"
-#include "components/feed/core/v2/test/proto_printer.h"
-#include "components/feed/core/v2/test/stream_builder.h"
-#include "components/feed/core/v2/test/test_util.h"
-#include "components/feed/core/v2/wire_response_translator.h"
-#include "components/feed/feed_feature_list.h"
-#include "components/leveldb_proto/public/proto_database_provider.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/page_criteria.h"
-#include "components/offline_pages/core/prefetch/stub_prefetch_service.h"
-#include "components/offline_pages/core/stub_offline_page_model.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/testing_pref_service.h"
-#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "services/network/test/test_url_loader_factory.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/zlib/google/compression_utils.h"
-
-namespace feed {
-namespace {
-
-std::unique_ptr<StreamModel> LoadModelFromStore(const StreamType& stream_type,
-                                                FeedStore* store) {
-  LoadStreamFromStoreTask::Result result;
-  auto complete = [&](LoadStreamFromStoreTask::Result task_result) {
-    result = std::move(task_result);
-  };
-  LoadStreamFromStoreTask load_task(
-      LoadStreamFromStoreTask::LoadType::kFullLoad, stream_type, store,
-      /*missed_last_refresh=*/false, base::BindLambdaForTesting(complete));
-  // We want to load the data no matter how stale.
-  load_task.IgnoreStalenessForTesting();
-
-  base::RunLoop run_loop;
-  load_task.Execute(run_loop.QuitClosure());
-  run_loop.Run();
-
-  if (result.status == LoadStreamStatus::kLoadedFromStore) {
-    auto model = std::make_unique<StreamModel>();
-    model->Update(std::move(result.update_request));
-    return model;
-  }
-  LOG(WARNING) << "LoadModelFromStore failed with " << result.status;
-  return nullptr;
-}
-
-// Returns the model state string (|StreamModel::DumpStateForTesting()|),
-// given a model initialized with |update_request| and having |operations|
-// applied.
-std::string ModelStateFor(
-    std::unique_ptr<StreamModelUpdateRequest> update_request,
-    std::vector<feedstore::DataOperation> operations = {},
-    std::vector<feedstore::DataOperation> more_operations = {}) {
-  StreamModel model;
-  model.Update(std::move(update_request));
-  model.ExecuteOperations(operations);
-  model.ExecuteOperations(more_operations);
-  return model.DumpStateForTesting();
-}
-
-// Returns the model state string (|StreamModel::DumpStateForTesting()|),
-// given a model initialized with |store|.
-std::string ModelStateFor(const StreamType& stream_type, FeedStore* store) {
-  auto model = LoadModelFromStore(stream_type, store);
-  if (model) {
-    return model->DumpStateForTesting();
-  }
-  return "{Failed to load model from store}";
-}
-
-feedwire::FeedAction MakeFeedAction(int64_t id, size_t pad_size = 0) {
-  feedwire::FeedAction action;
-
-  std::string pad;
-  if (pad_size > 0) {
-    pad = " " + std::string(pad_size - 1, 'a');
-  }
-
-  action.mutable_action_payload()->set_action_payload_data(
-      base::StrCat({base::NumberToString(id), pad}));
-  return action;
-}
-
-std::vector<feedstore::StoredAction> ReadStoredActions(FeedStore* store) {
-  base::RunLoop run_loop;
-  CallbackReceiver<std::vector<feedstore::StoredAction>> cr(&run_loop);
-  store->ReadActions(cr.Bind());
-  run_loop.Run();
-  CHECK(cr.GetResult());
-  return std::move(*cr.GetResult());
-}
-
-std::string SerializedOfflineBadgeContent() {
-  feedxsurface::OfflineBadgeContent testbadge;
-  std::string badge_serialized;
-  testbadge.set_available_offline(true);
-  testbadge.SerializeToString(&badge_serialized);
-  return badge_serialized;
-}
-
-feedwire::ThereAndBackAgainData MakeThereAndBackAgainData(int64_t id) {
-  feedwire::ThereAndBackAgainData msg;
-  *msg.mutable_action_payload() = MakeFeedAction(id).action_payload();
-  return msg;
-}
-
-class TestUnreadContentObserver : public FeedApi::UnreadContentObserver {
- public:
-  void HasUnreadContentChanged(bool has_unread_content) override {
-    calls.push_back(has_unread_content);
-  }
-
-  std::vector<bool> calls;
-};
-
-class TestSurfaceBase : public FeedStreamSurface {
- public:
-  // Provide some helper functionality to attach/detach the surface.
-  // This way we can auto-detach in the destructor.
-  explicit TestSurfaceBase(const StreamType& stream_type,
-                           FeedStream* stream = nullptr)
-      : FeedStreamSurface(stream_type) {
-    if (stream)
-      Attach(stream);
-  }
-
-  ~TestSurfaceBase() override {
-    if (stream_)
-      Detach();
-  }
-
-  void Attach(FeedStream* stream) {
-    EXPECT_FALSE(stream_);
-    stream_ = stream->GetWeakPtr();
-    stream_->AttachSurface(this);
-  }
-
-  void Detach() {
-    EXPECT_TRUE(stream_);
-    stream_->DetachSurface(this);
-    stream_ = nullptr;
-  }
-
-  // FeedStream::FeedStreamSurface.
-  void StreamUpdate(const feedui::StreamUpdate& stream_update) override {
-    DVLOG(1) << "StreamUpdate: " << stream_update;
-    // Some special-case treatment for the loading spinner. We don't count it
-    // toward |initial_state|.
-    bool is_initial_loading_spinner = IsInitialLoadSpinnerUpdate(stream_update);
-    if (!initial_state && !is_initial_loading_spinner) {
-      initial_state = stream_update;
-    }
-    update = stream_update;
-
-    described_updates_.push_back(CurrentState());
-  }
-  void ReplaceDataStoreEntry(base::StringPiece key,
-                             base::StringPiece data) override {
-    data_store_entries_[key.as_string()] = data.as_string();
-  }
-  void RemoveDataStoreEntry(base::StringPiece key) override {
-    data_store_entries_.erase(key.as_string());
-  }
-
-  // Test functions.
-
-  void Clear() {
-    initial_state = base::nullopt;
-    update = base::nullopt;
-    described_updates_.clear();
-  }
-
-  // Returns a description of the updates this surface received. Each update
-  // is separated by ' -> '. Returns only the updates since the last call.
-  std::string DescribeUpdates() {
-    std::string result = base::JoinString(described_updates_, " -> ");
-    described_updates_.clear();
-    return result;
-  }
-
-  std::map<std::string, std::string> GetDataStoreEntries() const {
-    return data_store_entries_;
-  }
-
-  // The initial state of the stream, if it was received. This is nullopt if
-  // only the loading spinner was seen.
-  base::Optional<feedui::StreamUpdate> initial_state;
-  // The last stream update received.
-  base::Optional<feedui::StreamUpdate> update;
-
- private:
-  std::string CurrentState() {
-    if (update && IsInitialLoadSpinnerUpdate(*update))
-      return "loading";
-
-    if (!initial_state)
-      return "empty";
-
-    bool has_loading_spinner = false;
-    for (int i = 0; i < update->updated_slices().size(); ++i) {
-      const feedui::StreamUpdate_SliceUpdate& slice_update =
-          update->updated_slices(i);
-      if (slice_update.has_slice() &&
-          slice_update.slice().has_zero_state_slice()) {
-        CHECK(update->updated_slices().size() == 1)
-            << "Zero state with other slices" << *update;
-        // Returns either "no-cards" or "cant-refresh".
-        return update->updated_slices()[0].slice().slice_id();
-      }
-      if (slice_update.has_slice() &&
-          slice_update.slice().has_loading_spinner_slice()) {
-        CHECK_EQ(i, update->updated_slices().size() - 1)
-            << "Loading spinner in an unexpected place" << *update;
-        has_loading_spinner = true;
-      }
-    }
-    std::stringstream ss;
-    if (has_loading_spinner) {
-      ss << update->updated_slices().size() - 1 << " slices +spinner";
-    } else {
-      ss << update->updated_slices().size() << " slices";
-    }
-    return ss.str();
-  }
-
-  bool IsInitialLoadSpinnerUpdate(const feedui::StreamUpdate& update) {
-    return update.updated_slices().size() == 1 &&
-           update.updated_slices()[0].has_slice() &&
-           update.updated_slices()[0].slice().has_loading_spinner_slice();
-  }
-
-  // The stream if it was attached using the constructor.
-  base::WeakPtr<FeedStream> stream_;
-  std::vector<std::string> described_updates_;
-  std::map<std::string, std::string> data_store_entries_;
-};
-
-class TestForYouSurface : public TestSurfaceBase {
- public:
-  explicit TestForYouSurface(FeedStream* stream = nullptr)
-      : TestSurfaceBase(kForYouStream, stream) {}
-};
-class TestWebFeedSurface : public TestSurfaceBase {
- public:
-  explicit TestWebFeedSurface(FeedStream* stream = nullptr)
-      : TestSurfaceBase(kWebFeedStream, stream) {}
-};
-
-class TestImageFetcher : public ImageFetcher {
- public:
-  explicit TestImageFetcher(
-      scoped_refptr<::network::SharedURLLoaderFactory> url_loader_factory)
-      : ImageFetcher(url_loader_factory) {}
-  ImageFetchId Fetch(
-      const GURL& url,
-      base::OnceCallback<void(NetworkResponse)> callback) override {
-    // Emulate a response.
-    NetworkResponse response = {"dummyresponse", 200};
-    std::move(callback).Run(std::move(response));
-    return id_generator_.GenerateNextId();
-  }
-  void Cancel(ImageFetchId id) override {}
-
- private:
-  ImageFetchId::Generator id_generator_;
-};
-
-class TestFeedNetwork : public FeedNetwork {
- public:
-  // FeedNetwork implementation.
-  void SendQueryRequest(
-      NetworkRequestType request_type,
-      const feedwire::Request& request,
-      bool force_signed_out_request,
-      base::OnceCallback<void(QueryRequestResult)> callback) override {
-    forced_signed_out_request = force_signed_out_request;
-    ++send_query_call_count;
-    // Emulate a successful response.
-    // The response body is currently an empty message, because most of the
-    // time we want to inject a translated response for ease of test-writing.
-    query_request_sent = request;
-    QueryRequestResult result;
-    result.response_info.status_code = 200;
-    result.response_info.response_body_bytes = 100;
-    result.response_info.fetch_duration = base::TimeDelta::FromMilliseconds(42);
-    result.response_info.was_signed_in = true;
-    if (injected_response_) {
-      result.response_body = std::make_unique<feedwire::Response>(
-          std::move(injected_response_.value()));
-    } else {
-      result.response_body = std::make_unique<feedwire::Response>();
-    }
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
-  }
-
-  void SendDiscoverApiRequest(
-      base::StringPiece api_path,
-      base::StringPiece method,
-      std::string request_bytes,
-      base::OnceCallback<void(RawResponse)> callback) override {
-    api_requests_sent_[api_path.as_string()] = request_bytes;
-    ++api_request_count_[api_path.as_string()];
-    std::vector<RawResponse>& injected_responses =
-        injected_api_responses_[api_path.as_string()];
-
-    // If there is no injected response, create a default response.
-    if (injected_responses.empty()) {
-      if (api_path == UploadActionsDiscoverApi::RequestPath()) {
-        feedwire::UploadActionsRequest request;
-        ASSERT_TRUE(request.ParseFromString(request_bytes));
-        feedwire::UploadActionsResponse response_message;
-        response_message.mutable_consistency_token()->set_token(
-            consistency_token);
-        InjectApiResponse<UploadActionsDiscoverApi>(response_message);
-      }
-    }
-
-    if (!injected_responses.empty()) {
-      RawResponse response = injected_responses[0];
-      injected_responses.erase(injected_responses.begin());
-      base::SequencedTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::BindOnce(std::move(callback), std::move(response)));
-      return;
-    }
-    ASSERT_TRUE(false)
-        << "No API response injected, and no default is available:" << api_path;
-  }
-
-  void CancelRequests() override { NOTIMPLEMENTED(); }
-
-  void InjectRealFeedQueryResponse() {
-    base::FilePath response_file_path;
-    CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &response_file_path));
-    response_file_path = response_file_path.AppendASCII(
-        "components/test/data/feed/response.binarypb");
-    std::string response_data;
-    CHECK(base::ReadFileToString(response_file_path, &response_data));
-
-    feedwire::Response response;
-    CHECK(response.ParseFromString(response_data));
-
-    injected_response_ = response;
-  }
-
-  template <typename API>
-  void InjectApiRawResponse(RawResponse result) {
-    injected_api_responses_[API::RequestPath().as_string()].push_back(result);
-  }
-
-  template <typename API>
-  void InjectApiResponse(const typename API::Response& response_message) {
-    RawResponse response;
-    response.response_info.status_code = 200;
-    response.response_bytes = response_message.SerializeAsString();
-    response.response_info.response_body_bytes = response.response_bytes.size();
-    InjectApiRawResponse<API>(std::move(response));
-  }
-
-  void InjectEmptyActionRequestResult() {
-    InjectApiRawResponse<UploadActionsDiscoverApi>({});
-  }
-
-  template <typename API>
-  base::Optional<typename API::Request> GetApiRequestSent() {
-    base::Optional<typename API::Request> result;
-    auto iter = api_requests_sent_.find(API::RequestPath().as_string());
-    if (iter != api_requests_sent_.end()) {
-      typename API::Request message;
-      if (!iter->second.empty()) {
-        if (!message.ParseFromString(iter->second)) {
-          LOG(ERROR) << "Failed to parse API request.";
-          return base::nullopt;
-        }
-      }
-      result = message;
-    }
-    return result;
-  }
-
-  base::Optional<feedwire::UploadActionsRequest> GetActionRequestSent() {
-    return GetApiRequestSent<UploadActionsDiscoverApi>();
-  }
-
-  template <typename API>
-  int GetApiRequestCount() const {
-    auto iter = api_request_count_.find(API::RequestPath().as_string());
-    return iter == api_request_count_.end() ? 0 : iter->second;
-  }
-  int GetActionRequestCount() const {
-    return GetApiRequestCount<UploadActionsDiscoverApi>();
-  }
-  void ClearTestData() {
-    injected_api_responses_.clear();
-    api_requests_sent_.clear();
-    api_request_count_.clear();
-    injected_response_.reset();
-  }
-
-  base::Optional<feedwire::Request> query_request_sent;
-  int send_query_call_count = 0;
-  std::string consistency_token;
-  bool forced_signed_out_request = false;
-
- private:
-  std::map<std::string, std::vector<RawResponse>> injected_api_responses_;
-  std::map<std::string, std::string> api_requests_sent_;
-  std::map<std::string, int> api_request_count_;
-  base::Optional<feedwire::Response> injected_response_;
-};
-
-// Forwards to |WireResponseTranslator| unless a response is
-// injected.
-class TestWireResponseTranslator : public WireResponseTranslator {
- public:
-  RefreshResponseData TranslateWireResponse(
-      feedwire::Response response,
-      StreamModelUpdateRequest::Source source,
-      bool was_signed_in_request,
-      base::Time current_time) const override {
-    if (!injected_responses_.empty()) {
-      if (injected_responses_[0].model_update_request)
-        injected_responses_[0].model_update_request->source = source;
-      RefreshResponseData result = std::move(injected_responses_[0]);
-      injected_responses_.erase(injected_responses_.begin());
-      return result;
-    }
-    return WireResponseTranslator::TranslateWireResponse(
-        std::move(response), source, was_signed_in_request, current_time);
-  }
-  void InjectResponse(std::unique_ptr<StreamModelUpdateRequest> response,
-                      base::Optional<std::string> session_id = base::nullopt) {
-    DCHECK(!response->stream_data.signed_in() || !session_id);
-    RefreshResponseData data;
-    data.model_update_request = std::move(response);
-    data.session_id = std::move(session_id);
-    InjectResponse(std::move(data));
-  }
-  void InjectResponse(RefreshResponseData response_data) {
-    injected_responses_.push_back(std::move(response_data));
-  }
-  bool InjectedResponseConsumed() const { return injected_responses_.empty(); }
-
- private:
-  mutable std::vector<RefreshResponseData> injected_responses_;
-};
-
-class FakeRefreshTaskScheduler : public RefreshTaskScheduler {
- public:
-  // RefreshTaskScheduler implementation.
-  void EnsureScheduled(RefreshTaskId id, base::TimeDelta run_time) override {
-    scheduled_run_times[id] = run_time;
-  }
-  void Cancel(RefreshTaskId id) override { canceled_tasks.insert(id); }
-  void RefreshTaskComplete(RefreshTaskId id) override {
-    completed_tasks.insert(id);
-  }
-
-  void Clear() {
-    scheduled_run_times.clear();
-    canceled_tasks.clear();
-    completed_tasks.clear();
-  }
-
-  std::map<RefreshTaskId, base::TimeDelta> scheduled_run_times;
-  std::set<RefreshTaskId> canceled_tasks;
-  std::set<RefreshTaskId> completed_tasks;
-
- private:
-  std::stringstream activity_log_;
-};
-
-class TestMetricsReporter : public MetricsReporter {
- public:
-  explicit TestMetricsReporter(PrefService* prefs) : MetricsReporter(prefs) {}
-
-  // MetricsReporter.
-  void ContentSliceViewed(const StreamType& stream_type,
-                          int index_in_stream) override {
-    slice_viewed_index = index_in_stream;
-    MetricsReporter::ContentSliceViewed(stream_type, index_in_stream);
-  }
-  void OnLoadStream(LoadStreamStatus load_from_store_status,
-                    LoadStreamStatus final_status,
-                    bool loaded_new_content_from_network,
-                    base::TimeDelta stored_content_age,
-                    std::unique_ptr<LoadLatencyTimes> latencies) override {
-    load_stream_from_store_status = load_from_store_status;
-    load_stream_status = final_status;
-    LOG(INFO) << "OnLoadStream: " << final_status
-              << " (store status: " << load_from_store_status << ")";
-    MetricsReporter::OnLoadStream(load_from_store_status, final_status,
-                                  loaded_new_content_from_network,
-                                  stored_content_age, std::move(latencies));
-  }
-  void OnLoadMoreBegin(SurfaceId surface_id) override {
-    load_more_surface_id = surface_id;
-    MetricsReporter::OnLoadMoreBegin(surface_id);
-  }
-  void OnLoadMore(LoadStreamStatus final_status) override {
-    load_more_status = final_status;
-    MetricsReporter::OnLoadMore(final_status);
-  }
-  void OnBackgroundRefresh(LoadStreamStatus final_status) override {
-    background_refresh_status = final_status;
-    MetricsReporter::OnBackgroundRefresh(final_status);
-  }
-  void OnClearAll(base::TimeDelta time_since_last_clear) override {
-    this->time_since_last_clear = time_since_last_clear;
-    MetricsReporter::OnClearAll(time_since_last_clear);
-  }
-  void OnUploadActions(UploadActionsStatus status) override {
-    upload_action_status = status;
-    MetricsReporter::OnUploadActions(status);
-  }
-
-  // Test access.
-
-  base::Optional<int> slice_viewed_index;
-  base::Optional<LoadStreamStatus> load_stream_status;
-  base::Optional<LoadStreamStatus> load_stream_from_store_status;
-  base::Optional<SurfaceId> load_more_surface_id;
-  base::Optional<LoadStreamStatus> load_more_status;
-  base::Optional<LoadStreamStatus> background_refresh_status;
-  base::Optional<base::TimeDelta> time_since_last_clear;
-  base::Optional<UploadActionsStatus> upload_action_status;
-};
-
-class TestPrefetchService : public offline_pages::StubPrefetchService {
- public:
-  TestPrefetchService() = default;
-  // offline_pages::StubPrefetchService.
-  void SetSuggestionProvider(
-      offline_pages::SuggestionsProvider* suggestions_provider) override {
-    suggestions_provider_ = suggestions_provider;
-  }
-  void NewSuggestionsAvailable() override {
-    ++new_suggestions_available_call_count_;
-  }
-
-  // Test functionality.
-  offline_pages::SuggestionsProvider* suggestions_provider() {
-    return suggestions_provider_;
-  }
-  int NewSuggestionsAvailableCallCount() const {
-    return new_suggestions_available_call_count_;
-  }
-
- private:
-  offline_pages::SuggestionsProvider* suggestions_provider_ = nullptr;
-  int new_suggestions_available_call_count_ = 0;
-};
-
-class TestOfflinePageModel : public offline_pages::StubOfflinePageModel {
- public:
-  // offline_pages::OfflinePageModel
-  void AddObserver(Observer* observer) override {
-    CHECK(observers_.insert(observer).second);
-  }
-  void RemoveObserver(Observer* observer) override {
-    CHECK_EQ(1UL, observers_.erase(observer));
-  }
-  void GetPagesWithCriteria(
-      const offline_pages::PageCriteria& criteria,
-      offline_pages::MultipleOfflinePageItemCallback callback) override {
-    std::vector<offline_pages::OfflinePageItem> result;
-    for (const offline_pages::OfflinePageItem& item : items_) {
-      if (MeetsCriteria(criteria, item)) {
-        result.push_back(item);
-      }
-    }
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback), result));
-  }
-
-  // Test functions.
-
-  void AddTestPage(const GURL& url) {
-    offline_pages::OfflinePageItem item;
-    item.url = url;
-    item.client_id =
-        offline_pages::ClientId(offline_pages::kSuggestedArticlesNamespace, "");
-    items_.push_back(item);
-  }
-
-  std::vector<offline_pages::OfflinePageItem>& items() { return items_; }
-
-  void CallObserverOfflinePageAdded(
-      const offline_pages::OfflinePageItem& item) {
-    for (Observer* observer : observers_) {
-      observer->OfflinePageAdded(this, item);
-    }
-  }
-
-  void CallObserverOfflinePageDeleted(
-      const offline_pages::OfflinePageItem& item) {
-    for (Observer* observer : observers_) {
-      observer->OfflinePageDeleted(item);
-    }
-  }
-
- private:
-  std::vector<offline_pages::OfflinePageItem> items_;
-  std::set<Observer*> observers_;
-};
-
-class FeedStreamTest : public testing::Test, public FeedStream::Delegate {
- public:
-  void SetUp() override {
-    SetupFeatures();
-    kTestTimeEpoch = base::Time::Now();
-
-    // Reset to default config, since tests can change it.
-    SetFeedConfigForTesting(Config());
-
-    feed::prefs::RegisterFeedSharedProfilePrefs(profile_prefs_.registry());
-    feed::RegisterProfilePrefs(profile_prefs_.registry());
-    metrics_reporter_ = std::make_unique<TestMetricsReporter>(&profile_prefs_);
-
-    shared_url_loader_factory_ =
-        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-            &test_factory_);
-    image_fetcher_ =
-        std::make_unique<TestImageFetcher>(shared_url_loader_factory_);
-
-    CreateStream();
-  }
-
-  virtual void SetupFeatures() {}
-
-  void TearDown() override {
-    // Ensure the task queue can return to idle. Failure to do so may be due
-    // to a stuck task that never called |TaskComplete()|.
-    WaitForIdleTaskQueue();
-    // ProtoDatabase requires PostTask to clean up.
-    store_.reset();
-    persistent_key_value_store_.reset();
-    task_environment_.RunUntilIdle();
-  }
-
-  // FeedStream::Delegate.
-  bool IsEulaAccepted() override { return is_eula_accepted_; }
-  bool IsOffline() override { return is_offline_; }
-  DisplayMetrics GetDisplayMetrics() override {
-    DisplayMetrics result;
-    result.density = 200;
-    result.height_pixels = 800;
-    result.width_pixels = 350;
-    return result;
-  }
-  std::string GetLanguageTag() override { return "en-US"; }
-  void ClearAll() override {}
-  bool IsSignedIn() override { return is_signed_in_; }
-  void PrefetchImage(const GURL& url) override {
-    prefetched_images_.push_back(url);
-    prefetch_image_call_count_++;
-  }
-  void RegisterExperiments(const Experiments& experiments) override {}
-
-  // For tests.
-
-  // Replace stream_.
-  void CreateStream() {
-    ChromeInfo chrome_info;
-    chrome_info.channel = version_info::Channel::STABLE;
-    chrome_info.version = base::Version({99, 1, 9911, 2});
-    stream_ = std::make_unique<FeedStream>(
-        &refresh_scheduler_, metrics_reporter_.get(), this, &profile_prefs_,
-        &network_, image_fetcher_.get(), store_.get(),
-        persistent_key_value_store_.get(), &prefetch_service_,
-        &offline_page_model_, chrome_info);
-
-    WaitForIdleTaskQueue();  // Wait for any initialization.
-    stream_->SetWireResponseTranslatorForTesting(&response_translator_);
-  }
-
-  bool IsTaskQueueIdle() const {
-    return !stream_->GetTaskQueueForTesting()->HasPendingTasks() &&
-           !stream_->GetTaskQueueForTesting()->HasRunningTask();
-  }
-
-  void WaitForIdleTaskQueue() {
-    if (IsTaskQueueIdle())
-      return;
-    base::test::ScopedRunLoopTimeout run_timeout(
-        FROM_HERE, base::TimeDelta::FromSeconds(1));
-    base::RunLoop run_loop;
-    stream_->SetIdleCallbackForTesting(run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  void UnloadModel(const StreamType& stream_type) {
-    WaitForIdleTaskQueue();
-    stream_->UnloadModel(stream_type);
-  }
-
-  // Dumps the state of |FeedStore| to a string for debugging.
-  std::string DumpStoreState(bool print_keys = false) {
-    base::RunLoop run_loop;
-    std::unique_ptr<std::map<std::string, feedstore::Record>> records;
-    auto callback =
-        [&](bool,
-            std::unique_ptr<std::map<std::string, feedstore::Record>> result) {
-          records = std::move(result);
-          run_loop.Quit();
-        };
-    store_->GetDatabaseForTesting()->LoadKeysAndEntries(
-        base::BindLambdaForTesting(callback));
-
-    run_loop.Run();
-    std::stringstream ss;
-    for (const auto& item : *records) {
-      if (print_keys)
-        ss << '"' << item.first << "\": ";
-
-      ss << item.second << '\n';
-    }
-    return ss.str();
-  }
-
-  void UploadActions(std::vector<feedwire::FeedAction> actions) {
-    size_t actions_remaining = actions.size();
-    for (feedwire::FeedAction& action : actions) {
-      stream_->UploadAction(action, (--actions_remaining) == 0ul,
-                            base::DoNothing());
-    }
-  }
-
- protected:
-  base::test::TaskEnvironment task_environment_{
-      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
-  TestingPrefServiceSimple profile_prefs_;
-  std::unique_ptr<TestMetricsReporter> metrics_reporter_;
-  TestFeedNetwork network_;
-  TestWireResponseTranslator response_translator_;
-  std::unique_ptr<TestImageFetcher> image_fetcher_;
-  network::TestURLLoaderFactory test_factory_;
-  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
-
-  std::unique_ptr<FeedStore> store_ = std::make_unique<FeedStore>(
-      leveldb_proto::ProtoDatabaseProvider::GetUniqueDB<feedstore::Record>(
-          leveldb_proto::ProtoDbType::FEED_STREAM_DATABASE,
-          /*db_dir=*/{},
-          task_environment_.GetMainThreadTaskRunner()));
-
-  std::unique_ptr<PersistentKeyValueStoreImpl> persistent_key_value_store_ =
-      std::make_unique<PersistentKeyValueStoreImpl>(
-          leveldb_proto::ProtoDatabaseProvider::GetUniqueDB<feedkvstore::Entry>(
-              leveldb_proto::ProtoDbType::FEED_KEY_VALUE_DATABASE,
-              /*db_dir=*/{},
-              task_environment_.GetMainThreadTaskRunner()));
-
-  FakeRefreshTaskScheduler refresh_scheduler_;
-  TestPrefetchService prefetch_service_;
-  TestOfflinePageModel offline_page_model_;
-  std::unique_ptr<FeedStream> stream_;
-  bool is_eula_accepted_ = true;
-  bool is_offline_ = false;
-  bool is_signed_in_ = true;
-  base::test::ScopedFeatureList scoped_feature_list_;
-  int prefetch_image_call_count_ = 0;
-  std::vector<GURL> prefetched_images_;
-};
-
-class FeedStreamTestForAllStreamTypes
-    : public FeedStreamTest,
-      public ::testing::WithParamInterface<StreamType> {
- public:
-  static StreamType GetStreamType() { return GetParam(); }
-  class TestSurface : public TestSurfaceBase {
-   public:
-    explicit TestSurface(FeedStream* stream = nullptr)
-        : TestSurfaceBase(FeedStreamTestForAllStreamTypes::GetStreamType(),
-                          stream) {}
-  };
-  RefreshTaskId GetRefreshTaskId() const {
-    RefreshTaskId id;
-    CHECK(GetStreamType().GetRefreshTaskId(id));
-    return id;
-  }
-};
-
-class FeedStreamConditionalActionsUploadTest : public FeedStreamTest {
-  void SetupFeatures() override {
-    scoped_feature_list_.InitAndEnableFeature(
-        feed::kInterestFeedV2ClicksAndViewsConditionalUpload);
-  }
-};
-
-TEST_F(FeedStreamTest, IsArticlesListVisibleByDefault) {
-  EXPECT_TRUE(stream_->IsArticlesListVisible());
-}
-
-TEST_F(FeedStreamTest, DoNotRefreshIfArticlesListIsHidden) {
-  profile_prefs_.SetBoolean(prefs::kArticlesListVisible, false);
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  EXPECT_FALSE(refresh_scheduler_.scheduled_run_times.count(
-      RefreshTaskId::kRefreshForYouFeed));
-  EXPECT_EQ(std::set<RefreshTaskId>({RefreshTaskId::kRefreshForYouFeed}),
-            refresh_scheduler_.completed_tasks);
-}
-
-TEST_F(FeedStreamTest, BackgroundRefreshForYouSuccess) {
-  // Trigger a background refresh.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  WaitForIdleTaskQueue();
-
-  // Verify the refresh happened and that we can load a stream without the
-  // network.
-  ASSERT_TRUE(refresh_scheduler_.completed_tasks.count(
-      RefreshTaskId::kRefreshForYouFeed));
-  EXPECT_EQ(LoadStreamStatus::kLoadedFromNetwork,
-            metrics_reporter_->background_refresh_status);
-  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
-  EXPECT_FALSE(stream_->GetModel(kForYouStream));
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  // Verify that prefetch service was informed.
-  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
-}
-
-TEST_F(FeedStreamTest, BackgroundRefreshWebFeedSuccess) {
-  // Trigger a background refresh.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshWebFeed);
-  WaitForIdleTaskQueue();
-
-  // Verify the refresh happened and that we can load a stream without the
-  // network.
-  ASSERT_TRUE(
-      refresh_scheduler_.completed_tasks.count(RefreshTaskId::kRefreshWebFeed));
-  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
-  TestWebFeedSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  // Verify that prefetch service is NOT informed.
-  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
-}
-
-TEST_F(FeedStreamTest, BackgroundRefreshPrefetchesImages) {
-  // Trigger a background refresh.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  EXPECT_EQ(0, prefetch_image_call_count_);
-  WaitForIdleTaskQueue();
-
-  std::vector<GURL> expected_fetches(
-      {GURL("http://image0/"), GURL("http://favicon0/"), GURL("http://image1/"),
-       GURL("http://favicon1/")});
-  // Verify that images were prefetched.
-  EXPECT_EQ(4, prefetch_image_call_count_);
-  EXPECT_EQ(expected_fetches, prefetched_images_);
-}
-
-TEST_F(FeedStreamTest, BackgroundRefreshNotAttemptedWhenModelIsLoading) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(metrics_reporter_->background_refresh_status,
-            LoadStreamStatus::kModelAlreadyLoaded);
-}
-
-TEST_F(FeedStreamTest, BackgroundRefreshNotAttemptedAfterModelIsLoaded) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(metrics_reporter_->background_refresh_status,
-            LoadStreamStatus::kModelAlreadyLoaded);
-}
-
-TEST_F(FeedStreamTest, SurfaceReceivesInitialContent) {
-  {
-    auto model = std::make_unique<StreamModel>();
-    model->Update(MakeTypicalInitialModelState());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
-  TestForYouSurface surface(stream_.get());
-  ASSERT_TRUE(surface.initial_state);
-  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
-  ASSERT_EQ(2, initial_state.updated_slices().size());
-  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
-  EXPECT_EQ("f:0", initial_state.updated_slices(0)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
-  EXPECT_EQ("f:1", initial_state.updated_slices(1)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-  ASSERT_EQ(1, initial_state.new_shared_states().size());
-  EXPECT_EQ("ss:0",
-            initial_state.new_shared_states()[0].xsurface_shared_state());
-}
-
-TEST_F(FeedStreamTest, SurfaceReceivesInitialContentLoadedAfterAttach) {
-  TestForYouSurface surface(stream_.get());
-  ASSERT_FALSE(surface.initial_state);
-  {
-    auto model = std::make_unique<StreamModel>();
-    model->Update(MakeTypicalInitialModelState());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
-
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
-
-  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
-  EXPECT_EQ("f:0", initial_state.updated_slices(0)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
-  EXPECT_EQ("f:1", initial_state.updated_slices(1)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-  ASSERT_EQ(1, initial_state.new_shared_states().size());
-  EXPECT_EQ("ss:0",
-            initial_state.new_shared_states()[0].xsurface_shared_state());
-}
-
-TEST_F(FeedStreamTest, SurfaceReceivesUpdatedContent) {
-  {
-    auto model = std::make_unique<StreamModel>();
-    model->ExecuteOperations(MakeTypicalStreamOperations());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
-  TestForYouSurface surface(stream_.get());
-  // Remove #1, add #2.
-  stream_->ExecuteOperations(
-      kForYouStream, {
-                         MakeOperation(MakeRemove(MakeClusterId(1))),
-                         MakeOperation(MakeCluster(2, MakeRootId())),
-                         MakeOperation(MakeContentNode(2, MakeClusterId(2))),
-                         MakeOperation(MakeContent(2)),
-                     });
-  ASSERT_TRUE(surface.update);
-  const feedui::StreamUpdate& initial_state = surface.initial_state.value();
-  const feedui::StreamUpdate& update = surface.update.value();
-
-  ASSERT_EQ("2 slices -> 2 slices", surface.DescribeUpdates());
-  // First slice is just an ID that matches the old 1st slice ID.
-  EXPECT_EQ(initial_state.updated_slices(0).slice().slice_id(),
-            update.updated_slices(0).slice_id());
-  // Second slice is a new xsurface slice.
-  EXPECT_NE("", update.updated_slices(1).slice().slice_id());
-  EXPECT_EQ("f:2",
-            update.updated_slices(1).slice().xsurface_slice().xsurface_frame());
-}
-
-TEST_F(FeedStreamTest, SurfaceReceivesSecondUpdatedContent) {
-  {
-    auto model = std::make_unique<StreamModel>();
-    model->ExecuteOperations(MakeTypicalStreamOperations());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
-  TestForYouSurface surface(stream_.get());
-  // Add #2.
-  stream_->ExecuteOperations(
-      kForYouStream, {
-                         MakeOperation(MakeCluster(2, MakeRootId())),
-                         MakeOperation(MakeContentNode(2, MakeClusterId(2))),
-                         MakeOperation(MakeContent(2)),
-                     });
-
-  // Clear the last update and add #3.
-  stream_->ExecuteOperations(
-      kForYouStream, {
-                         MakeOperation(MakeCluster(3, MakeRootId())),
-                         MakeOperation(MakeContentNode(3, MakeClusterId(3))),
-                         MakeOperation(MakeContent(3)),
-                     });
-
-  // The last update should have only one new piece of content.
-  // This verifies the current content set is tracked properly.
-  ASSERT_EQ("2 slices -> 3 slices -> 4 slices", surface.DescribeUpdates());
-
-  ASSERT_EQ(4, surface.update->updated_slices().size());
-  EXPECT_FALSE(surface.update->updated_slices(0).has_slice());
-  EXPECT_FALSE(surface.update->updated_slices(1).has_slice());
-  EXPECT_FALSE(surface.update->updated_slices(2).has_slice());
-  EXPECT_EQ("f:3", surface.update->updated_slices(3)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-}
-
-TEST_F(FeedStreamTest, RemoveAllContentResultsInZeroState) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Remove both pieces of content.
-  stream_->ExecuteOperations(kForYouStream,
-                             {
-                                 MakeOperation(MakeRemove(MakeClusterId(0))),
-                                 MakeOperation(MakeRemove(MakeClusterId(1))),
-                             });
-
-  ASSERT_EQ("loading -> 2 slices -> no-cards", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, DetachSurface) {
-  {
-    auto model = std::make_unique<StreamModel>();
-    model->ExecuteOperations(MakeTypicalStreamOperations());
-    stream_->LoadModelForTesting(kForYouStream, std::move(model));
-  }
-  TestForYouSurface surface(stream_.get());
-  EXPECT_TRUE(surface.initial_state);
-  surface.Detach();
-  surface.Clear();
-
-  // Arbitrary stream change. Surface should not see the update.
-  stream_->ExecuteOperations(kForYouStream,
-                             {
-                                 MakeOperation(MakeRemove(MakeClusterId(1))),
-                             });
-  EXPECT_FALSE(surface.update);
-}
-
-TEST_F(FeedStreamTest, FetchImage) {
-  CallbackReceiver<NetworkResponse> receiver;
-  stream_->FetchImage(GURL("https://example.com"), receiver.Bind());
-
-  EXPECT_EQ("dummyresponse", receiver.GetResult()->response_bytes);
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, LoadFromNetwork) {
-  {
-    auto metadata = stream_->GetMetadata();
-    metadata.set_consistency_token("token");
-    stream_->SetMetadata(metadata);
-  }
-
-  // Store is empty, so we should fallback to a network request.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_TRUE(network_.query_request_sent);
-  EXPECT_EQ(
-      "token",
-      network_.query_request_sent->feed_request().consistency_token().token());
-  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
-
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  // Verify the model is filled correctly.
-  EXPECT_STRINGS_EQUAL(
-      ModelStateFor(MakeTypicalInitialModelState()),
-      stream_->GetModel(GetStreamType())->DumpStateForTesting());
-  // Verify the data was written to the store.
-  EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()),
-                       ModelStateFor(GetStreamType(), store_.get()));
-}
-
-TEST_F(FeedStreamTest, ForceRefreshForDebugging) {
-  // First do a normal load via network that will fail.
-  is_offline_ = true;
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Next, force a refresh that results in a successful load.
-  is_offline_ = false;
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->ForceRefreshForDebugging();
-
-  WaitForIdleTaskQueue();
-  EXPECT_EQ("loading -> cant-refresh -> loading -> 2 slices",
-            surface.DescribeUpdates());
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, RefreshScheduleFlow) {
-  // Inject a typical network response, with a server-defined request schedule.
-  {
-    RequestSchedule schedule;
-    schedule.anchor_time = kTestTimeEpoch;
-    schedule.refresh_offsets = {base::TimeDelta::FromSeconds(12),
-                                base::TimeDelta::FromSeconds(48)};
-    RefreshResponseData response_data;
-    response_data.model_update_request = MakeTypicalInitialModelState();
-    response_data.request_schedule = schedule;
-
-    response_translator_.InjectResponse(std::move(response_data));
-
-    // Load the stream, and then destroy the surface to allow background
-    // refresh.
-    TestSurface surface(stream_.get());
-    WaitForIdleTaskQueue();
-    UnloadModel(surface.GetStreamType());
-  }
-
-  // Verify the first refresh was scheduled.
-  EXPECT_EQ(base::TimeDelta::FromSeconds(12),
-            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
-
-  // Simulate executing the background task.
-  refresh_scheduler_.Clear();
-  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(12));
-  stream_->ExecuteRefreshTask(GetRefreshTaskId());
-  WaitForIdleTaskQueue();
-
-  // Verify |RefreshTaskComplete()| was called and next refresh was scheduled.
-  EXPECT_TRUE(refresh_scheduler_.completed_tasks.count(GetRefreshTaskId()));
-  EXPECT_EQ(base::TimeDelta::FromSeconds(48 - 12),
-            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
-
-  // Simulate executing the background task again.
-  refresh_scheduler_.Clear();
-  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(48 - 12));
-  stream_->ExecuteRefreshTask(GetRefreshTaskId());
-  WaitForIdleTaskQueue();
-
-  // Verify |RefreshTaskComplete()| was called and next refresh was scheduled.
-  EXPECT_TRUE(refresh_scheduler_.completed_tasks.count(GetRefreshTaskId()));
-  EXPECT_EQ(GetFeedConfig().default_background_refresh_interval,
-            refresh_scheduler_.scheduled_run_times[GetRefreshTaskId()]);
-}
-
-TEST_F(FeedStreamTest, ForceRefreshIfMissedScheduledRefresh) {
-  // Inject a typical network response, with a server-defined request schedule.
-  {
-    RequestSchedule schedule;
-    schedule.anchor_time = kTestTimeEpoch;
-    schedule.refresh_offsets = {base::TimeDelta::FromSeconds(12),
-                                base::TimeDelta::FromSeconds(48)};
-    RefreshResponseData response_data;
-    response_data.model_update_request = MakeTypicalInitialModelState();
-    response_data.request_schedule = schedule;
-
-    response_translator_.InjectResponse(std::move(response_data));
-  }
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);
-  surface.Detach();
-  stream_->UnloadModel(surface.GetStreamType());
-
-  // Ensure a refresh is foreced only after a scheduled refresh was missed.
-  // First, load the stream after 11 seconds.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(11));
-  surface.Attach(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);  // no refresh yet
-
-  // Load the stream after 13 seconds. We missed the scheduled refresh at
-  // 12 seconds.
-  surface.Detach();
-  stream_->UnloadModel(surface.GetStreamType());
-  task_environment_.AdvanceClock(base::TimeDelta::FromSeconds(2));
-  surface.Attach(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_EQ(LoadStreamStatus::kDataInStoreStaleMissedLastRefresh,
-            metrics_reporter_->load_stream_from_store_status);
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, LoadFromNetworkBecauseStoreIsStale) {
-  // Fill the store with stream data that is just barely stale, and verify we
-  // fetch new data over the network.
-  store_->OverwriteStream(
-      GetStreamType(),
-      MakeTypicalInitialModelState(
-          /*first_cluster_id=*/0, kTestTimeEpoch -
-                                      GetFeedConfig().stale_content_threshold -
-                                      base::TimeDelta::FromMinutes(1)),
-      base::DoNothing());
-
-  // Store is stale, so we should fallback to a network request.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(network_.query_request_sent);
-  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
-  ASSERT_TRUE(surface.initial_state);
-}
-
-// Same as LoadFromNetworkBecauseStoreIsStale, but with expired content.
-TEST_F(FeedStreamTest, LoadFromNetworkBecauseStoreIsExpired) {
-  base::HistogramTester histograms;
-  const base::TimeDelta kContentAge =
-      GetFeedConfig().content_expiration_threshold +
-      base::TimeDelta::FromMinutes(1);
-  store_->OverwriteStream(
-      kForYouStream,
-      MakeTypicalInitialModelState(
-          /*first_cluster_id=*/0, kTestTimeEpoch - kContentAge),
-      base::DoNothing());
-
-  // Store is stale, so we should fallback to a network request.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(network_.query_request_sent);
-  EXPECT_TRUE(response_translator_.InjectedResponseConsumed());
-  ASSERT_TRUE(surface.initial_state);
-  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsExpired,
-            metrics_reporter_->load_stream_from_store_status);
-  histograms.ExpectUniqueTimeSample(
-      "ContentSuggestions.Feed.ContentAgeOnLoad.BlockingRefresh", kContentAge,
-      1);
-}
-
-TEST_F(FeedStreamTest, LoadStaleDataBecauseNetworkRequestFails) {
-  // Fill the store with stream data that is just barely stale.
-  base::HistogramTester histograms;
-  const base::TimeDelta kContentAge =
-      GetFeedConfig().stale_content_threshold + base::TimeDelta::FromMinutes(1);
-  store_->OverwriteStream(
-      kForYouStream,
-      MakeTypicalInitialModelState(
-          /*first_cluster_id=*/0, kTestTimeEpoch - kContentAge),
-      base::DoNothing());
-
-  // Store is stale, so we should fallback to a network request. Since we didn't
-  // inject a network response, the network update will fail.
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(network_.query_request_sent);
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsStale,
-            metrics_reporter_->load_stream_from_store_status);
-  EXPECT_EQ(LoadStreamStatus::kLoadedStaleDataFromStoreDueToNetworkFailure,
-            metrics_reporter_->load_stream_status);
-  histograms.ExpectUniqueTimeSample(
-      "ContentSuggestions.Feed.ContentAgeOnLoad.NotRefreshed", kContentAge, 1);
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, LoadFailsStoredDataIsExpired) {
-  // Fill the store with stream data that is just barely expired.
-  store_->OverwriteStream(
-      GetStreamType(),
-      MakeTypicalInitialModelState(
-          /*first_cluster_id=*/0,
-          kTestTimeEpoch - GetFeedConfig().content_expiration_threshold -
-              base::TimeDelta::FromMinutes(1)),
-      base::DoNothing());
-
-  // Store contains expired content, so we should fallback to a network request.
-  // Since we didn't inject a network response, the network update will fail.
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(network_.query_request_sent);
-  EXPECT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
-  EXPECT_EQ(LoadStreamStatus::kDataInStoreIsExpired,
-            metrics_reporter_->load_stream_from_store_status);
-  EXPECT_EQ(LoadStreamStatus::kProtoTranslationFailed,
-            metrics_reporter_->load_stream_status);
-}
-
-TEST_F(FeedStreamTest, LoadFromNetworkFailsDueToProtoTranslation) {
-  // No data in the store, so we should fetch from the network.
-  // The network will respond with an empty response, which should fail proto
-  // translation.
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(LoadStreamStatus::kProtoTranslationFailed,
-            metrics_reporter_->load_stream_status);
-  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
-}
-TEST_F(FeedStreamTest, DoNotLoadFromNetworkWhenOffline) {
-  is_offline_ = true;
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(LoadStreamStatus::kCannotLoadFromNetworkOffline,
-            metrics_reporter_->load_stream_status);
-  EXPECT_EQ("loading -> cant-refresh", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, DoNotLoadStreamWhenArticleListIsHidden) {
-  profile_prefs_.SetBoolean(prefs::kArticlesListVisible, false);
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(LoadStreamStatus::kLoadNotAllowedArticlesListHidden,
-            metrics_reporter_->load_stream_status);
-  EXPECT_EQ("no-cards", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, DoNotLoadStreamWhenEulaIsNotAccepted) {
-  is_eula_accepted_ = false;
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(LoadStreamStatus::kLoadNotAllowedEulaNotAccepted,
-            metrics_reporter_->load_stream_status);
-  EXPECT_EQ("no-cards", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, LoadStreamAfterEulaIsAccepted) {
-  // Connect a surface before the EULA is accepted.
-  is_eula_accepted_ = false;
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("no-cards", surface.DescribeUpdates());
-
-  // Accept EULA, our surface should receive data.
-  is_eula_accepted_ = true;
-  stream_->OnEulaAccepted();
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, ForceSignedOutRequestAfterHistoryIsDeleted) {
-  stream_->OnAllHistoryDeleted();
-
-  const std::string kSessionId = "session-id";
-
-  // This test injects response post translation/parsing. We have to configure
-  // the response data that should come out of the translator, which should
-  // mark the request/response as having been made from the signed-out state.
-  StreamModelUpdateRequestGenerator model_generator;
-  model_generator.signed_in = false;
-
-  // Advance the clock, but not past the end of the forced-signed-out period.
-  task_environment_.FastForwardBy(kSuppressRefreshDuration -
-                                  base::TimeDelta::FromSeconds(1));
-
-  // Refresh the feed, queuing up a signed-out response.
-  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
-                                      kSessionId);
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Validate that the network request was sent as signed out.
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_TRUE(network_.forced_signed_out_request);
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .chrome_client_info()
-                  .session_id()
-                  .empty());
-
-  // Validate the downstream consumption of the response.
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
-  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
-
-  // Advance the clock beyond the forced signed out period.
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
-  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType())->signed_in());
-
-  // Requests for subsequent pages continue the use existing session.
-  // Subsequent responses may omit the session id.
-  response_translator_.InjectResponse(model_generator.MakeNextPage());
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  // Validate that the network request was sent as signed out and
-  // contained the session id.
-  ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_TRUE(network_.forced_signed_out_request);
-  EXPECT_EQ(kSessionId, stream_->GetMetadata().session_id().token());
-  EXPECT_EQ(network_.query_request_sent->feed_request()
-                .client_info()
-                .chrome_client_info()
-                .session_id(),
-            kSessionId);
-
-  // The model should still be in the signed-out state.
-  EXPECT_FALSE(stream_->GetModel(kForYouStream)->signed_in());
-
-  // Force a refresh of the feed by clearing the cache. The request for the
-  // first page should revert back to signed-in. The response data will denote
-  // a signed-in response with no session_id.
-  model_generator.signed_in = true;
-  response_translator_.InjectResponse(model_generator.MakeFirstPage());
-  stream_->OnCacheDataCleared();
-  WaitForIdleTaskQueue();
-
-  // Validate that a signed-in request was sent.
-  ASSERT_EQ(3, network_.send_query_call_count);
-  EXPECT_FALSE(network_.forced_signed_out_request);
-
-  // The model should now be in the signed-in state.
-  EXPECT_TRUE(stream_->GetModel(kForYouStream)->signed_in());
-  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
-}
-
-TEST_F(FeedStreamTest, WebFeedUsesSignedInRequestAfterHistoryIsDeleted) {
-  stream_->OnAllHistoryDeleted();
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestWebFeedSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_FALSE(network_.forced_signed_out_request);
-}
-
-TEST_F(FeedStreamTest, AllowSignedInRequestAfterHistoryIsDeletedAfterDelay) {
-  stream_->OnAllHistoryDeleted();
-  task_environment_.FastForwardBy(kSuppressRefreshDuration +
-                                  base::TimeDelta::FromSeconds(1));
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  EXPECT_FALSE(network_.forced_signed_out_request);
-  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
-}
-
-TEST_F(FeedStreamTest, ShouldMakeFeedQueryRequestConsumesQuota) {
-  LoadStreamStatus status = LoadStreamStatus::kNoStatus;
-  for (; status == LoadStreamStatus::kNoStatus;
-       status = stream_->ShouldMakeFeedQueryRequest(kForYouStream)) {
-  }
-
-  ASSERT_EQ(LoadStreamStatus::kCannotLoadFromNetworkThrottled, status);
-}
-
-TEST_F(FeedStreamTest, LoadStreamFromStore) {
-  // Fill the store with stream data that is just barely fresh, and verify it
-  // loads.
-  store_->OverwriteStream(
-      kForYouStream,
-      MakeTypicalInitialModelState(
-          /*first_cluster_id=*/0, kTestTimeEpoch -
-                                      GetFeedConfig().stale_content_threshold +
-                                      base::TimeDelta::FromMinutes(1)),
-      base::DoNothing());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  EXPECT_FALSE(network_.query_request_sent);
-  // Verify the model is filled correctly.
-  EXPECT_STRINGS_EQUAL(ModelStateFor(MakeTypicalInitialModelState()),
-                       stream_->GetModel(kForYouStream)->DumpStateForTesting());
-}
-
-TEST_F(FeedStreamTest, LoadingSpinnerIsSentInitially) {
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-  TestForYouSurface surface(stream_.get());
-
-  ASSERT_EQ("loading", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, DetachSurfaceWhileLoadingModel) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  surface.Detach();
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ("loading", surface.DescribeUpdates());
-  EXPECT_TRUE(network_.query_request_sent);
-}
-
-TEST_F(FeedStreamTest, AttachMultipleSurfacesLoadsModelOnce) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  TestForYouSurface other_surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(1, network_.send_query_call_count);
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  ASSERT_EQ("loading -> 2 slices", other_surface.DescribeUpdates());
-
-  // After load, another surface doesn't trigger any tasks,
-  // and immediately has content.
-  TestForYouSurface later_surface(stream_.get());
-
-  ASSERT_EQ("2 slices", later_surface.DescribeUpdates());
-  EXPECT_TRUE(IsTaskQueueIdle());
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, ModelChangesAreSavedToStorage) {
-  store_->OverwriteStream(GetStreamType(), MakeTypicalInitialModelState(),
-                          base::DoNothing());
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_TRUE(surface.initial_state);
-
-  // Remove #1, add #2.
-  const std::vector<feedstore::DataOperation> operations = {
-      MakeOperation(MakeRemove(MakeClusterId(1))),
-      MakeOperation(MakeCluster(2, MakeRootId())),
-      MakeOperation(MakeContentNode(2, MakeClusterId(2))),
-      MakeOperation(MakeContent(2)),
-  };
-  stream_->ExecuteOperations(GetStreamType(), operations);
-
-  WaitForIdleTaskQueue();
-
-  // Verify changes are applied to storage.
-  EXPECT_STRINGS_EQUAL(
-      ModelStateFor(MakeTypicalInitialModelState(), operations),
-      ModelStateFor(GetStreamType(), store_.get()));
-
-  // Unload and reload the model from the store, and verify we can still apply
-  // operations correctly.
-  surface.Detach();
-  surface.Clear();
-  UnloadModel(GetStreamType());
-  surface.Attach(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_TRUE(surface.initial_state);
-
-  // Remove #2, add #3.
-  const std::vector<feedstore::DataOperation> operations2 = {
-      MakeOperation(MakeRemove(MakeClusterId(2))),
-      MakeOperation(MakeCluster(3, MakeRootId())),
-      MakeOperation(MakeContentNode(3, MakeClusterId(3))),
-      MakeOperation(MakeContent(3)),
-  };
-  stream_->ExecuteOperations(surface.GetStreamType(), operations2);
-
-  WaitForIdleTaskQueue();
-  EXPECT_STRINGS_EQUAL(
-      ModelStateFor(MakeTypicalInitialModelState(), operations, operations2),
-      ModelStateFor(GetStreamType(), store_.get()));
-}
-
-TEST_F(FeedStreamTest, ReportSliceViewedIdentifiesCorrectIndex) {
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-  EXPECT_EQ(1, metrics_reporter_->slice_viewed_index);
-}
-
-TEST_F(FeedStreamTest, ReportOpenInNewTabAction) {
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  base::UserActionTester user_actions;
-
-  stream_->ReportOpenInNewTabAction(
-      surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  EXPECT_EQ(1, user_actions.GetActionCount(
-                   "ContentSuggestions.Feed.CardAction.OpenInNewTab"));
-}
-
-TEST_F(FeedStreamTest, HasUnreadContentAfterLoadFromNetwork) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestUnreadContentObserver observer;
-  stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  TestForYouSurface surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(std::vector<bool>({true}), observer.calls);
-}
-
-TEST_F(FeedStreamTest, RemovedUnreadContentObserverDoesNotReceiveCalls) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestUnreadContentObserver observer;
-  stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  stream_->RemoveUnreadContentObserver(kForYouStream, &observer);
-  TestForYouSurface surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(std::vector<bool>(), observer.calls);
-}
-
-TEST_F(FeedStreamTest, DeletedUnreadContentObserverDoesNotCrash) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  {
-    TestUnreadContentObserver observer;
-    stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  }
-  TestForYouSurface surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-}
-
-TEST_F(FeedStreamTest, HasUnreadContentAfterLoadFromStore) {
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-
-  TestUnreadContentObserver observer;
-  stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  TestForYouSurface surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(std::vector<bool>({true}), observer.calls);
-}
-
-TEST_F(FeedStreamTest, ReportSliceViewedUpdatesObservers) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestUnreadContentObserver observer;
-  stream_->AddUnreadContentObserver(kForYouStream, &observer);
-  TestForYouSurface surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-  task_environment_.RunUntilIdle();
-
-  EXPECT_EQ(std::vector<bool>({true, false}), observer.calls);
-
-  // Verify that the fact the stream was viewed persists.
-  CreateStream();
-
-  TestUnreadContentObserver observer2;
-  stream_->AddUnreadContentObserver(kForYouStream, &observer2);
-  TestForYouSurface surface2(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(std::vector<bool>({false}), observer2.calls);
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, LoadMoreAppendsContent) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  // Load page 2.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-  // Ensure metrics reporter was informed at the start of the operation.
-  EXPECT_EQ(surface.GetSurfaceId(), metrics_reporter_->load_more_surface_id);
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-  EXPECT_EQ("2 slices +spinner -> 4 slices", surface.DescribeUpdates());
-
-  // Load page 3.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
-  stream_->LoadMore(surface, callback.Bind());
-
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-  EXPECT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
-  if (GetStreamType().IsForYou()) {
-    EXPECT_EQ(3, prefetch_service_.NewSuggestionsAvailableCallCount());
-  } else {
-    EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
-  }
-}
-
-TEST_P(FeedStreamTestForAllStreamTypes, LoadMorePersistsData) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  // Load page 2.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-
-  // Verify stored state is equivalent to in-memory model.
-  EXPECT_STRINGS_EQUAL(
-      stream_->GetModel(GetStreamType())->DumpStateForTesting(),
-      ModelStateFor(GetStreamType(), store_.get()));
-}
-
-TEST_F(FeedStreamTest, LoadMorePersistAndLoadMore) {
-  // Verify we can persist a LoadMore, and then do another LoadMore after
-  // reloading state.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  // Load page 2.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-
-  surface.Detach();
-  UnloadModel(kForYouStream);
-
-  // Load page 3.
-  surface.Attach(stream_.get());
-  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
-  WaitForIdleTaskQueue();
-  callback.Clear();
-  surface.Clear();
-  stream_->LoadMore(surface, callback.Bind());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-  ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
-  // Verify stored state is equivalent to in-memory model.
-  EXPECT_STRINGS_EQUAL(
-      stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(),
-      ModelStateFor(kForYouStream, store_.get()));
-}
-
-TEST_F(FeedStreamTest, LoadMoreSendsTokens) {
-  {
-    auto metadata = stream_->GetMetadata();
-    metadata.set_consistency_token("token");
-    stream_->SetMetadata(metadata);
-  }
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("2 slices +spinner -> 4 slices", surface.DescribeUpdates());
-
-  EXPECT_EQ(
-      "token",
-      network_.query_request_sent->feed_request().consistency_token().token());
-  EXPECT_EQ("page-2", network_.query_request_sent->feed_request()
-                          .feed_query()
-                          .next_page_token()
-                          .next_page_token()
-                          .next_page_token());
-
-  response_translator_.InjectResponse(MakeTypicalNextPageState(3));
-  stream_->LoadMore(surface, callback.Bind());
-
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("4 slices +spinner -> 6 slices", surface.DescribeUpdates());
-
-  EXPECT_EQ(
-      "token",
-      network_.query_request_sent->feed_request().consistency_token().token());
-  EXPECT_EQ("page-3", network_.query_request_sent->feed_request()
-                          .feed_query()
-                          .next_page_token()
-                          .next_page_token()
-                          .next_page_token());
-}
-
-TEST_F(FeedStreamTest, LoadMoreAbortsIfNoNextPageToken) {
-  {
-    std::unique_ptr<StreamModelUpdateRequest> initial_state =
-        MakeTypicalInitialModelState();
-    initial_state->stream_data.clear_next_page_token();
-    response_translator_.InjectResponse(std::move(initial_state));
-  }
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-  WaitForIdleTaskQueue();
-
-  // LoadMore fails, and does not make an additional request.
-  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-  EXPECT_EQ(base::nullopt, metrics_reporter_->load_more_surface_id)
-      << "metrics reporter was informed about a load more operation which "
-         "didn't begin";
-}
-
-TEST_F(FeedStreamTest, LoadMoreFail) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  // Don't inject another response, which results in a proto translation
-  // failure.
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
-  EXPECT_EQ("2 slices +spinner -> 2 slices", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, LoadMoreWithClearAllInResponse) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-
-  // Use a different initial state (which includes a CLEAR_ALL).
-  response_translator_.InjectResponse(MakeTypicalInitialModelState(5));
-  CallbackReceiver<bool> callback;
-  stream_->LoadMore(surface, callback.Bind());
-
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(base::Optional<bool>(true), callback.GetResult());
-
-  // Verify stored state is equivalent to in-memory model.
-  EXPECT_STRINGS_EQUAL(
-      stream_->GetModel(surface.GetStreamType())->DumpStateForTesting(),
-      ModelStateFor(kForYouStream, store_.get()));
-
-  // Verify the new state has been pushed to |surface|.
-  ASSERT_EQ("2 slices +spinner -> 2 slices", surface.DescribeUpdates());
-
-  const feedui::StreamUpdate& initial_state = surface.update.value();
-  ASSERT_EQ(2, initial_state.updated_slices().size());
-  EXPECT_NE("", initial_state.updated_slices(0).slice().slice_id());
-  EXPECT_EQ("f:5", initial_state.updated_slices(0)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-  EXPECT_NE("", initial_state.updated_slices(1).slice().slice_id());
-  EXPECT_EQ("f:6", initial_state.updated_slices(1)
-                       .slice()
-                       .xsurface_slice()
-                       .xsurface_frame());
-}
-
-TEST_F(FeedStreamTest, LoadMoreBeforeLoad) {
-  CallbackReceiver<bool> callback;
-  TestForYouSurface surface;
-  stream_->LoadMore(surface, callback.Bind());
-
-  EXPECT_EQ(base::Optional<bool>(false), callback.GetResult());
-}
-
-TEST_F(FeedStreamTest, ReadNetworkResponse) {
-  base::HistogramTester histograms;
-  network_.InjectRealFeedQueryResponse();
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 10 slices", surface.DescribeUpdates());
-
-  // Verify we're processing some of the data on the request.
-
-  // The response has a privacy_notice_fulfilled=true.
-  histograms.ExpectUniqueSample(
-      "ContentSuggestions.Feed.ActivityLoggingEnabled", 1, 1);
-
-  // A request schedule with two entries was in the response. The first entry
-  // should have already been scheduled/consumed, leaving only the second
-  // entry still in the the refresh_offsets vector.
-  RequestSchedule schedule = prefs::GetRequestSchedule(
-      RefreshTaskId::kRefreshForYouFeed, profile_prefs_);
-  EXPECT_EQ(std::vector<base::TimeDelta>({
-                base::TimeDelta::FromSeconds(86308) +
-                    base::TimeDelta::FromNanoseconds(822963644),
-                base::TimeDelta::FromSeconds(120000),
-            }),
-            schedule.refresh_offsets);
-
-  // The stream's user attributes are set, so activity logging is enabled.
-  EXPECT_TRUE(stream_->IsActivityLoggingEnabled());
-  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
-}
-
-TEST_F(FeedStreamTest, ClearAllAfterLoadResultsInRefresh) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->OnCacheDataCleared();  // triggers ClearAll().
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ("loading -> 2 slices -> loading -> 2 slices",
-            surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, ClearAllWithNoSurfacesAttachedDoesNotReload) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  surface.Detach();
-
-  stream_->OnCacheDataCleared();  // triggers ClearAll().
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ("loading -> 2 slices", surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, ClearAllWhileLoadingMore) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->LoadMore(surface, base::DoNothing());
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->OnCacheDataCleared();  // triggers ClearAll().
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(
-      "loading -> 2 slices -> 2 slices +spinner -> 4 slices -> loading -> 2 "
-      "slices",
-      surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, ClearAllWipesAllState) {
-  // Trigger saving a consistency token, so it can be cleared later.
-  network_.consistency_token = "token-11";
-  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
-  // Trigger saving a feed stream, so it can be cleared later.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Enqueue an action, so it can be cleared later.
-  stream_->UploadAction(MakeFeedAction(43ul), false, base::DoNothing());
-
-  // Trigger ClearAll, this should erase everything.
-  stream_->OnCacheDataCleared();
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 2 slices -> loading -> cant-refresh",
-            surface.DescribeUpdates());
-
-  EXPECT_EQ("{\n}\n\n", DumpStoreState());
-  EXPECT_EQ("", stream_->GetMetadata().consistency_token());
-  EXPECT_FALSE(stream_->IsActivityLoggingEnabled());
-}
-
-TEST_F(FeedStreamTest, StorePendingAction) {
-  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  std::vector<feedstore::StoredAction> result =
-      ReadStoredActions(stream_->GetStore());
-  ASSERT_EQ(1ul, result.size());
-
-  EXPECT_EQ(ToTextProto(MakeFeedAction(42ul).action_payload()),
-            ToTextProto(result[0].action().action_payload()));
-}
-
-TEST_F(FeedStreamTest, UploadActionWhileSignedOutIsNoOp) {
-  is_signed_in_ = false;
-  stream_->UploadAction(MakeFeedAction(42ul), false, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
-}
-
-TEST_F(FeedStreamTest, SignOutWhileUploadActionDoesNotUpload) {
-  stream_->UploadAction(MakeFeedAction(42ul), true, base::DoNothing());
-  is_signed_in_ = false;
-
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(UploadActionsStatus::kAbortUploadForSignedOutUser,
-            metrics_reporter_->upload_action_status);
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-}
-
-TEST_F(FeedStreamTest, StorePendingActionAndUploadNow) {
-  network_.consistency_token = "token-11";
-
-  // Call |ProcessThereAndBackAgain()|, which triggers Upload() with
-  // upload_now=true.
-  {
-    feedwire::ThereAndBackAgainData msg;
-    *msg.mutable_action_payload() = MakeFeedAction(42ul).action_payload();
-    stream_->ProcessThereAndBackAgain(msg.SerializeAsString());
-  }
-  WaitForIdleTaskQueue();
-
-  // Verify the action was uploaded.
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-  std::vector<feedstore::StoredAction> result =
-      ReadStoredActions(stream_->GetStore());
-  ASSERT_EQ(0ul, result.size());
-}
-
-TEST_F(FeedStreamTest, ProcessViewActionResultsInDelayedUpload) {
-  network_.consistency_token = "token-11";
-
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  // Verify it's not uploaded immediately.
-  ASSERT_EQ(0, network_.GetActionRequestCount());
-
-  // Trigger a network refresh.
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Verify the action was uploaded.
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-}
-
-TEST_F(FeedStreamTest, ActionsUploadWithoutConditionsWhenFeatureDisabled) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  stream_->ProcessViewAction(
-      feedwire::FeedAction::default_instance().SerializeAsString());
-  WaitForIdleTaskQueue();
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Verify the actions were uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       NoActionsUploadUntilReachedConditions) {
-  // Tests the flow where we:
-  //   (1) Perform a ThereAndBackAgain action and a View action while upload
-  //   isn't enabled => (2) Attempt an upload while the upload conditions aren't
-  //   reached => (3) Reach upload conditions => (4) Perform another View action
-  //   that should be dropped => (5) Simulate the backgrounding of the app to
-  //   enable actions upload => (6) Trigger an upload which will upload the
-  //   stored ThereAndBackAgain action.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Process the view action and the ThereAndBackAgain action while the upload
-  // conditions aren't reached.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  // Verify that the view action was dropped.
-  ASSERT_EQ(0ul, ReadStoredActions(stream_->GetStore()).size());
-
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  // Verify that the ThereAndBackAgain action is in the action store.
-  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
-  // Attempt an upload.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  // Verify that no upload is done because the conditions aren't reached.
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Verify that the view action is still dropped because we haven't
-  // transitioned out of the current surface.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1ul, ReadStoredActions(stream_->GetStore()).size());
-
-  // Enable the upload bit and trigger the upload of actions.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded but not the view
-  // action.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnSurfaceAttached) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Perform a ThereAndBackAgain action.
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Attach a new surface to update the bit to enable uploads.
-  TestForYouSurface surface2(stream_.get());
-
-  // Trigger an upload through load more to isolate the effect of the on-attach
-  // event on enabling uploads.
-  response_translator_.InjectResponse(MakeTypicalNextPageState());
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest, EnableUploadOnEnterBackground) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Perform a ThereAndBackAgain action.
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that the ThereAndBackAgain action was uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       AllowActionsUploadWhenNoticeCardNotPresentRegardlessOfConditions) {
-  auto model_state = MakeTypicalInitialModelState();
-  model_state->stream_data.set_privacy_notice_fulfilled(false);
-  response_translator_.InjectResponse(std::move(model_state));
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Process the view action and the ThereAndBackAgain action while the upload
-  // conditions aren't reached.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-  stream_->ProcessThereAndBackAgain(
-      MakeThereAndBackAgainData(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Trigger an upload through a query.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify the ThereAndBackAgain action and the view action were uploaded.
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(2, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       ReupdateUploadEnableBitsOnSignIn) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Assert that uploads are not yet enabled.
-  ASSERT_FALSE(stream_->CanUploadActions());
-
-  // Update the upload enable bits which will enable upload because the related
-  // pref is true.
-  stream_->OnSignedIn();
-
-  EXPECT_TRUE(stream_->CanUploadActions());
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       ResetTheUploadEnableBitsOnSignOut) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Update the upload enable bits which will enable upload.
-  stream_->OnSignedOut();
-
-  ASSERT_TRUE(stream_->CanUploadActions());
-}
-
-TEST_F(FeedStreamTest, LoadStreamUpdateNoticeCardFulfillmentHistogram) {
-  base::HistogramTester histograms;
-
-  // Trigger a stream refresh that updates the histogram.
-  {
-    auto model_state = MakeTypicalInitialModelState();
-    model_state->stream_data.set_privacy_notice_fulfilled(false);
-    response_translator_.InjectResponse(std::move(model_state));
-
-    refresh_scheduler_.Clear();
-    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-    WaitForIdleTaskQueue();
-  }
-
-  UnloadModel(kForYouStream);
-
-  // Trigger another stream refresh that updates the histogram.
-  {
-    auto model_state = MakeTypicalInitialModelState();
-    model_state->stream_data.set_privacy_notice_fulfilled(true);
-    response_translator_.InjectResponse(std::move(model_state));
-
-    refresh_scheduler_.Clear();
-    stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-    WaitForIdleTaskQueue();
-  }
-
-  // Verify that the notice card fulfillment histogram was properly recorded.
-  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
-                               0, 1);
-  histograms.ExpectBucketCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
-                               1, 1);
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       DontTriggerActionsUploadWhenWasNotSignedIn) {
-  auto update_request = MakeTypicalInitialModelState();
-  update_request->stream_data.set_signed_in(false);
-  response_translator_.InjectResponse(std::move(update_request));
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Try to reach conditions.
-  stream_->ReportSliceViewed(
-      surface.GetSurfaceId(), surface.GetStreamType(),
-      surface.initial_state->updated_slices(1).slice().slice_id());
-
-  // Try to trigger an upload through a query.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that even if the conditions were reached, the pref that enables the
-  // upload wasn't set to true because the latest refresh request wasn't signed
-  // in.
-  ASSERT_FALSE(stream_->CanUploadActions());
-}
-
-TEST_F(FeedStreamTest, LoadStreamFromNetworkUploadsActions) {
-  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-
-  // Uploaded action should have been erased from store.
-  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(2, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamTest, UploadedActionsHaveSequentialNumbers) {
-  // Send 3 actions.
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
-  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
-  stream_->UploadAction(MakeFeedAction(3ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-  feedwire::UploadActionsRequest request1 = *network_.GetActionRequestSent();
-
-  // Send another action in a new request.
-  stream_->UploadAction(MakeFeedAction(4ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(2, network_.GetActionRequestCount());
-  feedwire::UploadActionsRequest request2 = *network_.GetActionRequestSent();
-
-  // Verify that sent actions have sequential numbers.
-  ASSERT_EQ(3, request1.feed_actions_size());
-  ASSERT_EQ(1, request2.feed_actions_size());
-
-  EXPECT_EQ(1, request1.feed_actions(0).client_data().sequence_number());
-  EXPECT_EQ(2, request1.feed_actions(1).client_data().sequence_number());
-  EXPECT_EQ(3, request1.feed_actions(2).client_data().sequence_number());
-  EXPECT_EQ(4, request2.feed_actions(0).client_data().sequence_number());
-}
-
-TEST_F(FeedStreamTest, LoadMoreUploadsActions) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->UploadAction(MakeFeedAction(99ul), false, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  network_.consistency_token = "token-12";
-
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-  EXPECT_EQ("token-12", stream_->GetMetadata().consistency_token());
-
-  // Uploaded action should have been erased from the store.
-  network_.ClearTestData();
-  stream_->UploadAction(MakeFeedAction(100ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-
-  EXPECT_EQ(
-      ToTextProto(MakeFeedAction(100ul).action_payload()),
-      ToTextProto(
-          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
-}
-
-TEST_F(FeedStreamTest, LoadMoreUpdatesIsActivityLoggingEnabled) {
-  EXPECT_FALSE(stream_->IsActivityLoggingEnabled());
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->IsActivityLoggingEnabled());
-
-  int page = 2;
-  for (bool signed_in : {true, false}) {
-    for (bool waa_on : {true, false}) {
-      for (bool privacy_notice_fulfilled : {true, false}) {
-        response_translator_.InjectResponse(
-            MakeTypicalNextPageState(page++, kTestTimeEpoch, signed_in, waa_on,
-                                     privacy_notice_fulfilled));
-        CallbackReceiver<bool> callback;
-        stream_->LoadMore(surface, callback.Bind());
-        WaitForIdleTaskQueue();
-        EXPECT_EQ(
-            stream_->IsActivityLoggingEnabled(),
-            (signed_in && waa_on) ||
-                (!signed_in && GetFeedConfig().send_signed_out_session_logs))
-            << "signed_in=" << signed_in << " waa_on=" << waa_on
-            << " privacy_notice_fulfilled=" << privacy_notice_fulfilled
-            << " send_signed_out_session_logs="
-            << GetFeedConfig().send_signed_out_session_logs;
-      }
-    }
-  }
-}
-
-TEST_F(FeedStreamConditionalActionsUploadTest,
-       LoadMoreDoesntUpdateNoticeCardPrefAndHistogram) {
-  // The initial stream load has the notice card.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Inject a response for the LoadMore fetch that doesn't have the notice card.
-  // It shouldn't overwrite the notice card pref.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(
-      /* first_cluster_id= */ 0,
-      /* last_added_time= */ kTestTimeEpoch,
-      /* logging_enabled= */ true,
-      /* privacy_notice_fulfilled= */ false));
-
-  // Start tracking histograms after the initial stream load to isolate the
-  // effect of load more.
-  base::HistogramTester histograms;
-
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  // Process a view action that should be dropped because the upload of actions
-  // is still disabled because there is still a notice card.
-  stream_->ProcessViewAction(MakeFeedAction(42ul).SerializeAsString());
-  WaitForIdleTaskQueue();
-
-  // Trigger an upload.
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-
-  // Verify that there were no uploads.
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-
-  // Verify that the notice card fulfillment histogram isn't recorded for load
-  // more.
-  histograms.ExpectTotalCount("ContentSuggestions.Feed.NoticeCardFulfilled2",
-                              0);
-}
-
-TEST_F(FeedStreamTest, BackgroundingAppUploadsActions) {
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-  EXPECT_EQ(
-      ToTextProto(MakeFeedAction(1ul).action_payload()),
-      ToTextProto(
-          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
-}
-
-TEST_F(FeedStreamTest, BackgroundingAppDoesNotUploadActions) {
-  Config config;
-  config.upload_actions_on_enter_background = false;
-  SetFeedConfigForTesting(config);
-
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(0, network_.GetActionRequestCount());
-}
-
-TEST_F(FeedStreamTest, UploadedActionsAreNotSentAgain) {
-  stream_->UploadAction(MakeFeedAction(1ul), false, base::DoNothing());
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.GetActionRequestCount());
-
-  stream_->OnEnterBackground();
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-}
-
-TEST_F(FeedStreamTest, UploadActionsOneBatch) {
-  UploadActions(
-      {MakeFeedAction(97ul), MakeFeedAction(98ul), MakeFeedAction(99ul)});
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
-
-  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(2, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamTest, UploadActionsMultipleBatches) {
-  UploadActions({
-      // Batch 1: One really big action.
-      MakeFeedAction(100ul, /*pad_size=*/20001ul),
-
-      // Batch 2
-      MakeFeedAction(101ul, 10000ul),
-      MakeFeedAction(102ul, 9000ul),
-
-      // Batch 3. Trigger upload.
-      MakeFeedAction(103ul, 2000ul),
-  });
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ(3, network_.GetActionRequestCount());
-
-  stream_->UploadAction(MakeFeedAction(99ul), true, base::DoNothing());
-  WaitForIdleTaskQueue();
-  EXPECT_EQ(4, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-}
-
-TEST_F(FeedStreamTest, UploadActionsSkipsStaleActionsByTimestamp) {
-  stream_->UploadAction(MakeFeedAction(2ul), false, base::DoNothing());
-  WaitForIdleTaskQueue();
-  task_environment_.FastForwardBy(base::TimeDelta::FromHours(25));
-
-  // Trigger upload
-  CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
-  WaitForIdleTaskQueue();
-
-  // Just one action should have been uploaded.
-  EXPECT_EQ(1, network_.GetActionRequestCount());
-  EXPECT_EQ(1, network_.GetActionRequestSent()->feed_actions_size());
-  EXPECT_EQ(
-      ToTextProto(MakeFeedAction(3ul).action_payload()),
-      ToTextProto(
-          network_.GetActionRequestSent()->feed_actions(0).action_payload()));
-
-  ASSERT_TRUE(cr.GetResult());
-  EXPECT_EQ(1ul, cr.GetResult()->upload_attempt_count);
-  EXPECT_EQ(1ul, cr.GetResult()->stale_count);
-}
-
-TEST_F(FeedStreamTest, UploadActionsErasesStaleActionsByAttempts) {
-  // Three failed uploads, plus one more to cause the first action to be erased.
-  network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(0ul), true, base::DoNothing());
-  network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(1ul), true, base::DoNothing());
-  network_.InjectEmptyActionRequestResult();
-  stream_->UploadAction(MakeFeedAction(2ul), true, base::DoNothing());
-
-  CallbackReceiver<UploadActionsTask::Result> cr;
-  stream_->UploadAction(MakeFeedAction(3ul), true, cr.Bind());
-  WaitForIdleTaskQueue();
-
-  // Four requests, three pending actions in the last request.
-  EXPECT_EQ(4, network_.GetActionRequestCount());
-  EXPECT_EQ(3, network_.GetActionRequestSent()->feed_actions_size());
-
-  // Action 0 should have been erased.
-  ASSERT_TRUE(cr.GetResult());
-  EXPECT_EQ(3ul, cr.GetResult()->upload_attempt_count);
-  EXPECT_EQ(1ul, cr.GetResult()->stale_count);
-}
-
-TEST_F(FeedStreamTest, MetadataLoadedWhenDatabaseInitialized) {
-  const auto kExpiry = kTestTimeEpoch + base::TimeDelta::FromDays(1234);
-  {
-    // Write some metadata so it can be loaded when FeedStream starts up.
-    feedstore::Metadata initial_metadata;
-    feedstore::SetSessionId(initial_metadata, "session-id", kExpiry);
-    initial_metadata.set_consistency_token("token");
-    store_->WriteMetadata(initial_metadata, base::DoNothing());
-  }
-
-  // Creating a stream should load metadata.
-  CreateStream();
-
-  EXPECT_EQ("session-id", stream_->GetMetadata().session_id().token());
-  EXPECT_TIME_EQ(kExpiry,
-                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
-  EXPECT_EQ("token", stream_->GetMetadata().consistency_token());
-  // Verify the schema has been updated to the current version.
-  EXPECT_EQ((int)FeedStore::kCurrentStreamSchemaVersion,
-            stream_->GetMetadata().stream_schema_version());
-}
-
-TEST_F(FeedStreamTest, ModelUnloadsAfterTimeout) {
-  Config config;
-  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
-  SetFeedConfigForTesting(config);
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  surface.Detach();
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
-  WaitForIdleTaskQueue();
-  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
-}
-
-TEST_F(FeedStreamTest, ModelDoesNotUnloadIfSurfaceIsAttached) {
-  Config config;
-  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
-  SetFeedConfigForTesting(config);
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  surface.Detach();
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
-
-  surface.Attach(stream_.get());
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
-}
-
-TEST_F(FeedStreamTest, ModelUnloadsAfterSecondTimeout) {
-  Config config;
-  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
-  SetFeedConfigForTesting(config);
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  surface.Detach();
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
-
-  // Attaching another surface will prolong the unload time for another second.
-  surface.Attach(stream_.get());
-  surface.Detach();
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(999));
-  WaitForIdleTaskQueue();
-  EXPECT_TRUE(stream_->GetModel(surface.GetStreamType()));
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
-  WaitForIdleTaskQueue();
-  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
-}
-
-TEST_F(FeedStreamTest, ProvidesPrefetchSuggestionsWhenModelLoaded) {
-  // Setup by triggering a model load.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Because we loaded from the network,
-  // PrefetchService::NewSuggestionsAvailable() should have been called.
-  EXPECT_EQ(1, prefetch_service_.NewSuggestionsAvailableCallCount());
-
-  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
-  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
-      callback.Bind());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(callback.GetResult());
-  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
-      callback.GetResult().value();
-
-  ASSERT_EQ(2UL, suggestions.size());
-  EXPECT_EQ("http://content0/", suggestions[0].article_url);
-  EXPECT_EQ("title0", suggestions[0].article_title);
-  EXPECT_EQ("publisher0", suggestions[0].article_attribution);
-  EXPECT_EQ("snippet0", suggestions[0].article_snippet);
-  EXPECT_EQ("http://image0/", suggestions[0].thumbnail_url);
-  EXPECT_EQ("http://favicon0/", suggestions[0].favicon_url);
-
-  EXPECT_EQ("http://content1/", suggestions[1].article_url);
-}
-
-TEST_F(FeedStreamTest, ProvidesPrefetchSuggestionsWhenModelNotLoaded) {
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-
-  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
-  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
-      callback.Bind());
-  WaitForIdleTaskQueue();
-
-  ASSERT_FALSE(stream_->GetModel(kForYouStream));
-  ASSERT_TRUE(callback.GetResult());
-  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
-      callback.GetResult().value();
-
-  ASSERT_EQ(2UL, suggestions.size());
-  EXPECT_EQ("http://content0/", suggestions[0].article_url);
-  EXPECT_EQ("http://content1/", suggestions[1].article_url);
-  EXPECT_EQ(0, prefetch_service_.NewSuggestionsAvailableCallCount());
-}
-
-TEST_F(FeedStreamTest, ScrubsUrlsInProvidedPrefetchSuggestions) {
-  {
-    auto initial_state = MakeTypicalInitialModelState();
-    initial_state->content[0].mutable_prefetch_metadata(0)->set_uri(
-        "?notavalidurl?");
-    initial_state->content[0].mutable_prefetch_metadata(0)->set_image_url(
-        "?asdf?");
-    initial_state->content[0].mutable_prefetch_metadata(0)->set_favicon_url(
-        "?hi?");
-    initial_state->content[0].mutable_prefetch_metadata(0)->clear_uri();
-    store_->OverwriteStream(kForYouStream, std::move(initial_state),
-                            base::DoNothing());
-  }
-
-  CallbackReceiver<std::vector<offline_pages::PrefetchSuggestion>> callback;
-  prefetch_service_.suggestions_provider()->GetCurrentArticleSuggestions(
-      callback.Bind());
-  WaitForIdleTaskQueue();
-
-  ASSERT_TRUE(callback.GetResult());
-  const std::vector<offline_pages::PrefetchSuggestion>& suggestions =
-      callback.GetResult().value();
-
-  ASSERT_EQ(2UL, suggestions.size());
-  EXPECT_EQ("", suggestions[0].article_url.possibly_invalid_spec());
-  EXPECT_EQ("", suggestions[0].thumbnail_url.possibly_invalid_spec());
-  EXPECT_EQ("", suggestions[0].favicon_url.possibly_invalid_spec());
-}
-
-TEST_F(FeedStreamTest, OfflineBadgesArePopulatedInitially) {
-  // Add two offline pages. We exclude tab-bound pages, so only the first is
-  // used.
-  offline_page_model_.AddTestPage(GURL("http://content0/"));
-  offline_page_model_.AddTestPage(GURL("http://content1/"));
-  offline_page_model_.items()[1].client_id.name_space =
-      offline_pages::kLastNNamespace;
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ((std::map<std::string, std::string>(
-                {{"app/badge0", SerializedOfflineBadgeContent()}})),
-            surface.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, OfflineBadgesArePopulatedOnNewOfflineItemAdded) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ((std::map<std::string, std::string>({})),
-            surface.GetDataStoreEntries());
-
-  // Add an offline page.
-  offline_page_model_.AddTestPage(GURL("http://content1/"));
-  offline_page_model_.CallObserverOfflinePageAdded(
-      offline_page_model_.items()[0]);
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
-
-  EXPECT_EQ((std::map<std::string, std::string>(
-                {{"app/badge1", SerializedOfflineBadgeContent()}})),
-            surface.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, OfflineBadgesAreRemovedWhenOfflineItemRemoved) {
-  offline_page_model_.AddTestPage(GURL("http://content0/"));
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ((std::map<std::string, std::string>(
-                {{"app/badge0", SerializedOfflineBadgeContent()}})),
-            surface.GetDataStoreEntries());
-
-  // Remove the offline page.
-  offline_page_model_.CallObserverOfflinePageDeleted(
-      offline_page_model_.items()[0]);
-  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
-
-  EXPECT_EQ((std::map<std::string, std::string>()),
-            surface.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, OfflineBadgesAreProvidedToNewSurfaces) {
-  offline_page_model_.AddTestPage(GURL("http://content0/"));
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  TestForYouSurface surface2(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ((std::map<std::string, std::string>(
-                {{"app/badge0", SerializedOfflineBadgeContent()}})),
-            surface2.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, OfflineBadgesAreRemovedWhenModelIsUnloaded) {
-  offline_page_model_.AddTestPage(GURL("http://content0/"));
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  stream_->UnloadModel(surface.GetStreamType());
-
-  // Offline badge no longer present.
-  EXPECT_EQ((std::map<std::string, std::string>()),
-            surface.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, MultipleOfflineBadgesWithSameUrl) {
-  {
-    std::unique_ptr<StreamModelUpdateRequest> state =
-        MakeTypicalInitialModelState();
-    const feedwire::PrefetchMetadata& prefetch_metadata1 =
-        state->content[0].prefetch_metadata(0);
-    feedwire::PrefetchMetadata& prefetch_metadata2 =
-        *state->content[0].add_prefetch_metadata();
-    prefetch_metadata2 = prefetch_metadata1;
-    prefetch_metadata2.set_badge_id("app/badge0b");
-    response_translator_.InjectResponse(std::move(state));
-  }
-  offline_page_model_.AddTestPage(GURL("http://content0/"));
-
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EXPECT_EQ((std::map<std::string, std::string>(
-                {{"app/badge0", SerializedOfflineBadgeContent()},
-                 {"app/badge0b", SerializedOfflineBadgeContent()}})),
-            surface.GetDataStoreEntries());
-}
-
-TEST_F(FeedStreamTest, SendsClientInstanceId) {
-  // Store is empty, so we should fallback to a network request.
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(1, network_.send_query_call_count);
-  ASSERT_TRUE(network_.query_request_sent);
-
-  // Instance ID is a random token. Verify it is not empty.
-  std::string first_instance_id = network_.query_request_sent->feed_request()
-                                      .client_info()
-                                      .client_instance_id();
-  EXPECT_NE("", first_instance_id);
-
-  // No signed-out session id was in the request.
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .chrome_client_info()
-                  .session_id()
-                  .empty());
-
-  // LoadMore, and verify the same token is used.
-  response_translator_.InjectResponse(MakeTypicalNextPageState(2));
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_EQ(first_instance_id, network_.query_request_sent->feed_request()
-                                   .client_info()
-                                   .client_instance_id());
-
-  // No signed-out session id was in the request.
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .chrome_client_info()
-                  .session_id()
-                  .empty());
-
-  // Trigger a ClearAll to verify the instance ID changes.
-  stream_->OnSignedOut();
-  WaitForIdleTaskQueue();
-
-  EXPECT_FALSE(stream_->GetModel(surface.GetStreamType()));
-  const bool is_for_next_page = false;  // No model so no first page yet.
-  const std::string new_instance_id =
-      stream_->GetRequestMetadata(kForYouStream, is_for_next_page)
-          .client_instance_id;
-  ASSERT_NE("", new_instance_id);
-  ASSERT_NE(first_instance_id, new_instance_id);
-}
-
-TEST_F(FeedStreamTest, LoadStreamSendsNoticeCardAcknowledgement) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      feed::kInterestFeedNoticeCardAutoDismiss);
-
-  store_->OverwriteStream(kForYouStream, MakeTypicalInitialModelState(),
-                          base::DoNothing());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  // Generate 3 view actions and 1 click action to trigger the acknowledgement
-  // of the notice card.
-  const int notice_card_index = 0;
-  std::string slice_id =
-      surface.initial_state->updated_slices(notice_card_index)
-          .slice()
-          .slice_id();
-  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
-                             slice_id);
-  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
-                             slice_id);
-  stream_->ReportSliceViewed(surface.GetSurfaceId(), surface.GetStreamType(),
-                             slice_id);
-  stream_->ReportOpenAction(surface.GetStreamType(), slice_id);
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  stream_->UnloadModel(surface.GetStreamType());
-  stream_->ExecuteRefreshTask(RefreshTaskId::kRefreshForYouFeed);
-  WaitForIdleTaskQueue();
-
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .feed_query()
-                  .chrome_fulfillment_info()
-                  .notice_card_acknowledged());
-}
-
-TEST_F(FeedStreamTest, SignedOutSessionIdConsistency) {
-  const std::string kSessionToken1("session-token-1");
-  const std::string kSessionToken2("session-token-2");
-
-  is_signed_in_ = false;
-
-  StreamModelUpdateRequestGenerator model_generator;
-  model_generator.signed_in = false;
-
-  // (1) Do an initial load of the store
-  //     - this should trigger a network request
-  //     - the request should not include client-instance-id
-  //     - the request should not include a session-id
-  //     - the stream should capture the session-id token from the response
-  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
-                                      kSessionToken1);
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .client_instance_id()
-                  .empty());
-  EXPECT_FALSE(network_.query_request_sent->feed_request()
-                   .client_info()
-                   .has_chrome_client_info());
-  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
-  const base::Time kSessionToken1ExpiryTime =
-      feedstore::GetSessionIdExpiryTime(stream_->GetMetadata());
-
-  // (2) LoadMore: the server returns the same session-id token
-  //     - this should trigger a network request
-  //     - the request should not include client-instance-id
-  //     - the request should include the first session-id
-  //     - the stream should retain the first session-id
-  //     - the session-id's expiry time should be unchanged
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  response_translator_.InjectResponse(model_generator.MakeNextPage(2),
-                                      kSessionToken1);
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .client_instance_id()
-                  .empty());
-  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
-                                .client_info()
-                                .chrome_client_info()
-                                .session_id());
-  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
-  EXPECT_TIME_EQ(kSessionToken1ExpiryTime,
-                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
-
-  // (3) LoadMore: the server omits returning a session-id token
-  //     - this should trigger a network request
-  //     - the request should not include client-instance-id
-  //     - the request should include the first session-id
-  //     - the stream should retain the first session-id
-  //     - the session-id's expiry time should be unchanged
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  response_translator_.InjectResponse(model_generator.MakeNextPage(3));
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(3, network_.send_query_call_count);
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .client_instance_id()
-                  .empty());
-  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
-                                .client_info()
-                                .chrome_client_info()
-                                .session_id());
-  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
-  EXPECT_TIME_EQ(kSessionToken1ExpiryTime,
-                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
-
-  // (4) LoadMore: the server returns new session id.
-  //     - this should trigger a network request
-  //     - the request should not include client-instance-id
-  //     - the request should include the first session-id
-  //     - the stream should retain the second session-id
-  //     - the new session-id's expiry time should be updated
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
-  response_translator_.InjectResponse(model_generator.MakeNextPage(4),
-                                      kSessionToken2);
-  stream_->LoadMore(surface, base::DoNothing());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(4, network_.send_query_call_count);
-  EXPECT_TRUE(network_.query_request_sent->feed_request()
-                  .client_info()
-                  .client_instance_id()
-                  .empty());
-  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
-                                .client_info()
-                                .chrome_client_info()
-                                .session_id());
-  EXPECT_EQ(kSessionToken2, stream_->GetMetadata().session_id().token());
-  EXPECT_TIME_EQ(kSessionToken1ExpiryTime + base::TimeDelta::FromSeconds(3),
-                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
-}
-
-TEST_F(FeedStreamTest, ClearAllResetsSessionId) {
-  is_signed_in_ = false;
-
-  // Initialize a session id.
-  feedstore::Metadata metadata = stream_->GetMetadata();
-  metadata = *feedstore::MaybeUpdateSessionId(metadata, "session-id");
-  stream_->SetMetadata(metadata);
-
-  // Trigger a ClearAll.
-  stream_->OnCacheDataCleared();
-  WaitForIdleTaskQueue();
-
-  // Session-ID should be wiped.
-  EXPECT_TRUE(stream_->GetMetadata().session_id().token().empty());
-  EXPECT_TRUE(
-      feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()).is_null());
-}
-
-TEST_F(FeedStreamTest, SignedOutSessionIdExpiry) {
-  const std::string kSessionToken1("session-token-1");
-  const std::string kSessionToken2("session-token-2");
-
-  is_signed_in_ = false;
-
-  StreamModelUpdateRequestGenerator model_generator;
-  model_generator.signed_in = false;
-
-  // (1) Do an initial load of the store
-  //     - this should trigger a network request
-  //     - the request should not include a session-id
-  //     - the stream should capture the session-id token from the response
-  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
-                                      kSessionToken1);
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_FALSE(network_.query_request_sent->feed_request()
-                   .client_info()
-                   .has_chrome_client_info());
-  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
-
-  // (2) Reload the stream from the network:
-  //     - Detach the surface, advance the clock beyond the stale content
-  //       threshold, re-attach the surface.
-  //     - this should trigger a network request
-  //     - the request should include kSessionToken1
-  //     - the stream should retain the original session-id
-  surface.Detach();
-  task_environment_.FastForwardBy(GetFeedConfig().stale_content_threshold +
-                                  base::TimeDelta::FromSeconds(1));
-  response_translator_.InjectResponse(model_generator.MakeFirstPage());
-  surface.Attach(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(2, network_.send_query_call_count);
-  EXPECT_EQ(kSessionToken1, network_.query_request_sent->feed_request()
-                                .client_info()
-                                .chrome_client_info()
-                                .session_id());
-  EXPECT_EQ(kSessionToken1, stream_->GetMetadata().session_id().token());
-
-  // (3) Reload the stream from the network:
-  //     - Detach the surface, advance the clock beyond the session id max age
-  //       threshold, re-attach the surface.
-  //     - this should trigger a network request
-  //     - the request should not include a session-id
-  //     - the stream should get a new session-id
-  surface.Detach();
-  task_environment_.FastForwardBy(GetFeedConfig().session_id_max_age -
-                                  GetFeedConfig().stale_content_threshold);
-  ASSERT_LT(feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()),
-            base::Time::Now());
-  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
-                                      kSessionToken2);
-  surface.Attach(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(3, network_.send_query_call_count);
-  EXPECT_FALSE(network_.query_request_sent->feed_request()
-                   .client_info()
-                   .has_chrome_client_info());
-  EXPECT_EQ(kSessionToken2, stream_->GetMetadata().session_id().token());
-}
-
-TEST_F(FeedStreamTest, SessionIdPersistsAcrossStreamLoads) {
-  const std::string kSessionToken("session-token-ftw");
-  const base::Time kExpiryTime =
-      kTestTimeEpoch + GetFeedConfig().session_id_max_age;
-
-  StreamModelUpdateRequestGenerator model_generator;
-  model_generator.signed_in = false;
-  is_signed_in_ = false;
-
-  // (1) Do an initial load of the store
-  //     - this should trigger a network request
-  //     - the stream should capture the session-id token from the response
-  response_translator_.InjectResponse(model_generator.MakeFirstPage(),
-                                      kSessionToken);
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);
-
-  // (2) Reload the metadata from disk.
-  //     - the network query call count should be unchanged
-  //     - the session token and expiry time should have been reloaded.
-  surface.Detach();
-  CreateStream();
-  WaitForIdleTaskQueue();
-  ASSERT_EQ(1, network_.send_query_call_count);
-  EXPECT_EQ(kSessionToken, stream_->GetMetadata().session_id().token());
-  EXPECT_TIME_EQ(kExpiryTime,
-                 feedstore::GetSessionIdExpiryTime(stream_->GetMetadata()));
-}
-
-TEST_F(FeedStreamTest, PersistentKeyValueStoreIsClearedOnClearAll) {
-  // Store some data and verify it exists.
-  PersistentKeyValueStore* store = stream_->GetPersistentKeyValueStore();
-  store->Put("x", "y", base::DoNothing());
-  CallbackReceiver<PersistentKeyValueStore::Result> get_result;
-  store->Get("x", get_result.Bind());
-  ASSERT_EQ("y", *get_result.RunAndGetResult().get_result);
-
-  stream_->OnCacheDataCleared();  // triggers ClearAll().
-  WaitForIdleTaskQueue();
-
-  // Verify ClearAll() deleted the data.
-  get_result.Clear();
-  store->Get("x", get_result.Bind());
-  EXPECT_FALSE(get_result.RunAndGetResult().get_result);
-}
-
-TEST_F(FeedStreamTest, LoadMultipleStreams) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface for_you_surface(stream_.get());
-  TestWebFeedSurface web_feed_surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 2 slices", for_you_surface.DescribeUpdates());
-  ASSERT_EQ("loading -> 2 slices", web_feed_surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, UnloadOnlyOneOfMultipleModels) {
-  Config config;
-  config.model_unload_timeout = base::TimeDelta::FromSeconds(1);
-  SetFeedConfigForTesting(config);
-
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface for_you_surface(stream_.get());
-  TestWebFeedSurface web_feed_surface(stream_.get());
-
-  WaitForIdleTaskQueue();
-
-  for_you_surface.Detach();
-
-  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
-  WaitForIdleTaskQueue();
-
-  EXPECT_TRUE(stream_->GetModel(kWebFeedStream));
-  EXPECT_FALSE(stream_->GetModel(kForYouStream));
-}
-
-TEST_F(FeedStreamTest, ExperimentsAreClearedOnClearAll) {
-  Experiments e;
-  e["Trial1"] = "Group1";
-  e["Trial2"] = "Group2";
-  prefs::SetExperiments(e, profile_prefs_);
-
-  stream_->OnCacheDataCleared();  // triggers ClearAll().
-  WaitForIdleTaskQueue();
-
-  Experiments empty;
-  Experiments got = prefs::GetExperiments(profile_prefs_);
-  EXPECT_EQ(got, empty);
-}
-
-TEST_F(FeedStreamTest, CreateAndCommitEphemeralChange) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EphemeralChangeId change_id = stream_->CreateEphemeralChange(
-      surface.GetStreamType(), {MakeOperation(MakeClearAll())});
-  stream_->CommitEphemeralChange(surface.GetStreamType(), change_id);
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 2 slices -> no-cards -> no-cards",
-            surface.DescribeUpdates());
-}
-
-TEST_F(FeedStreamTest, RejectEphemeralChange) {
-  response_translator_.InjectResponse(MakeTypicalInitialModelState());
-  TestForYouSurface surface(stream_.get());
-  WaitForIdleTaskQueue();
-
-  EphemeralChangeId change_id = stream_->CreateEphemeralChange(
-      surface.GetStreamType(), {MakeOperation(MakeClearAll())});
-  stream_->RejectEphemeralChange(surface.GetStreamType(), change_id);
-  WaitForIdleTaskQueue();
-
-  ASSERT_EQ("loading -> 2 slices -> no-cards -> 2 slices",
-            surface.DescribeUpdates());
-}
-
-// Keep instantiations at the bottom.
-INSTANTIATE_TEST_SUITE_P(FeedStreamTest,
-                         FeedStreamTestForAllStreamTypes,
-                         ::testing::Values(kForYouStream, kWebFeedStream),
-                         ::testing::PrintToStringParamName());
-
-}  // namespace
-}  // namespace feed
diff --git a/components/full_restore/arc_read_handler.cc b/components/full_restore/arc_read_handler.cc
index d8b1f98b6..bdf7cb8 100644
--- a/components/full_restore/arc_read_handler.cc
+++ b/components/full_restore/arc_read_handler.cc
@@ -7,6 +7,7 @@
 #include "components/full_restore/full_restore_info.h"
 #include "components/full_restore/full_restore_read_handler.h"
 #include "components/full_restore/window_info.h"
+#include "ui/aura/window.h"
 
 namespace full_restore {
 
@@ -20,6 +21,27 @@
   window_id_to_app_id_[window_id] = app_id;
 }
 
+void ArcReadHandler::AddArcWindowCandidate(aura::Window* window) {
+  arc_window_candidates_.insert(window);
+}
+
+void ArcReadHandler::OnWindowDestroyed(aura::Window* window) {
+  DCHECK(window);
+
+  // If |window| is list in |arc_window_candidates_|, |window| is not attached
+  // to a valid restore window id yet, so we don't need to remove AppRestoreData
+  // from the restore data.
+  auto it = arc_window_candidates_.find(window);
+  if (it != arc_window_candidates_.end()) {
+    arc_window_candidates_.erase(it);
+    return;
+  }
+
+  int32_t restore_window_id =
+      window->GetProperty(::full_restore::kRestoreWindowIdKey);
+  RemoveAppRestoreData(restore_window_id);
+}
+
 void ArcReadHandler::OnTaskCreated(const std::string& app_id,
                                    int32_t task_id,
                                    int32_t session_id) {
@@ -30,6 +52,22 @@
   int32_t restore_window_id = it->second;
   session_id_to_window_id_.erase(it);
   task_id_to_window_id_[task_id] = restore_window_id;
+
+  // Go through |arc_window_candidates_|. If the window for |task_id| has been
+  // created, set the correct restore window id, and remove the window from the
+  // hidden container.
+  auto window_it = std::find_if(
+      arc_window_candidates_.begin(), arc_window_candidates_.end(),
+      [task_id](aura::Window* window) {
+        return window->GetProperty(::full_restore::kWindowIdKey) == task_id;
+      });
+  if (window_it != arc_window_candidates_.end()) {
+    (*window_it)
+        ->SetProperty(full_restore::kRestoreWindowIdKey, restore_window_id);
+    (*window_it)->SetProperty(full_restore::kParentToHiddenContainerKey, false);
+    FullRestoreInfo::GetInstance()->OnWindowInitialized(*window_it);
+    arc_window_candidates_.erase(*window_it);
+  }
 }
 
 void ArcReadHandler::OnTaskDestroyed(int32_t task_id) {
@@ -47,6 +85,19 @@
   return base::Contains(window_id_to_app_id_, window_id);
 }
 
+std::unique_ptr<WindowInfo> ArcReadHandler::GetWindowInfo(
+    int32_t restore_window_id) {
+  if (restore_window_id == 0 || restore_window_id == kParentToHiddenContainer)
+    return nullptr;
+
+  auto it = window_id_to_app_id_.find(restore_window_id);
+  if (it == window_id_to_app_id_.end())
+    return nullptr;
+
+  return FullRestoreReadHandler::GetInstance()->GetWindowInfo(
+      profile_path_, it->second, restore_window_id);
+}
+
 int32_t ArcReadHandler::GetArcRestoreWindowId(int32_t task_id) {
   auto it = task_id_to_window_id_.find(task_id);
   if (it != task_id_to_window_id_.end())
diff --git a/components/full_restore/arc_read_handler.h b/components/full_restore/arc_read_handler.h
index 6ed6889..2761ac0 100644
--- a/components/full_restore/arc_read_handler.h
+++ b/components/full_restore/arc_read_handler.h
@@ -6,13 +6,21 @@
 #define COMPONENTS_FULL_RESTORE_ARC_READ_HANDLER_H_
 
 #include <map>
+#include <set>
+#include <utility>
 
 #include "base/component_export.h"
 #include "base/files/file_path.h"
 #include "components/full_restore/full_restore_utils.h"
 
+namespace aura {
+class Window;
+}
+
 namespace full_restore {
 
+struct WindowInfo;
+
 // ArcReadHandler is a helper class for FullRestoreReadHandler to handle ARC app
 // windows special cases, e.g. ARC task creation, ARC session id, etc.
 class COMPONENT_EXPORT(FULL_RESTORE) ArcReadHandler {
@@ -26,6 +34,12 @@
   // there is a restore data for |app_id| and |window_id|.
   void AddRestoreData(const std::string& app_id, int32_t window_id);
 
+  // Add |window| to |arc_window_candidates_|.
+  void AddArcWindowCandidate(aura::Window* window);
+
+  // Invoked when |window| is destroyed.
+  void OnWindowDestroyed(aura::Window* window);
+
   // Invoked when the task is created for an ARC app.
   void OnTaskCreated(const std::string& app_id,
                      int32_t task_id,
@@ -38,6 +52,9 @@
   // false.
   bool HasRestoreData(int32_t window_id);
 
+  // Gets the window information for |restore_window_id|.
+  std::unique_ptr<WindowInfo> GetWindowInfo(int32_t restore_window_id);
+
   // Returns the restore window id for the ARC app's |task_id|.
   int32_t GetArcRestoreWindowId(int32_t task_id);
 
@@ -69,6 +86,12 @@
 
   // The map from the arc task id to the window id.
   std::map<int32_t, int32_t> task_id_to_window_id_;
+
+  // ARC app tasks could be created after the window initialized.
+  // |arc_window_candidates_| is used to record those initialized ARC app
+  // windows, whose tasks have not been created. Once the task for the window is
+  // created, the window is removed from |arc_window_candidates_|.
+  std::set<aura::Window*> arc_window_candidates_;
 };
 
 }  // namespace full_restore
diff --git a/components/full_restore/full_restore_read_and_save_unittest.cc b/components/full_restore/full_restore_read_and_save_unittest.cc
index 5ffc88d..f53808c6 100644
--- a/components/full_restore/full_restore_read_and_save_unittest.cc
+++ b/components/full_restore/full_restore_read_and_save_unittest.cc
@@ -199,6 +199,15 @@
     full_restore::SaveWindowInfo(window_info);
   }
 
+  std::unique_ptr<WindowInfo> GetArcWindowInfo(int32_t restore_window_id) {
+    std::unique_ptr<aura::Window> window(
+        aura::test::CreateTestWindowWithId(restore_window_id, nullptr));
+    window->SetProperty(aura::client::kAppType,
+                        static_cast<int>(ash::AppType::ARC_APP));
+    window->SetProperty(full_restore::kRestoreWindowIdKey, restore_window_id);
+    return full_restore::GetWindowInfo(window.get());
+  }
+
   void VerifyRestoreData(const base::FilePath& file_path,
                          int32_t id,
                          int32_t index) {
@@ -478,6 +487,11 @@
   read_handler->SetArcSessionIdForWindowId(kArcSessionId2, kArcTaskId1);
   EXPECT_EQ(1u, read_test_api.GetArcSessionIdMap().size());
 
+  // Before OnTaskCreated is called, return -1 to add the ARC app window to the
+  // hidden container.
+  EXPECT_EQ(kParentToHiddenContainer,
+            full_restore::GetArcRestoreWindowId(kArcTaskId2));
+
   // Call OnTaskCreated to simulate that the ARC app with |kAppId| has been
   // launched, and the new task id |kArcTaskId2| has been created with
   // |kArcSessionId2| returned.
@@ -490,6 +504,11 @@
   EXPECT_TRUE(read_test_api.GetArcSessionIdMap().empty());
   EXPECT_EQ(kArcTaskId1, full_restore::GetArcRestoreWindowId(kArcTaskId2));
 
+  // Verify |window_info| for |kArcTaskId1|.
+  auto window_info = GetArcWindowInfo(kArcTaskId1);
+  EXPECT_TRUE(window_info);
+  EXPECT_EQ(kActivationIndex1, window_info->activation_index);
+
   // Call OnTaskDestroyed to simulate the ARC app launching has been finished
   // for |kArcTaskId2|, and verify the task id map is now empty and a invalid
   // value is returned when trying to get the restore window id.
diff --git a/components/full_restore/full_restore_read_handler.cc b/components/full_restore/full_restore_read_handler.cc
index 1b7cdce..be8c697 100644
--- a/components/full_restore/full_restore_read_handler.cc
+++ b/components/full_restore/full_restore_read_handler.cc
@@ -45,8 +45,16 @@
     if (!arc_read_handler_)
       return;
 
-    if (arc_read_handler_->HasRestoreData(window_id)) {
+    if (window_id == kParentToHiddenContainer ||
+        arc_read_handler_->HasRestoreData(window_id)) {
       observed_windows_.AddObservation(window);
+
+      // If |window| is added to a hidden container, that means the ARC task is
+      // not created yet, so add |window| to |arc_window_candidates_| to wait
+      // the task to be created.
+      if (window_id == kParentToHiddenContainer)
+        arc_read_handler_->AddArcWindowCandidate(window);
+
       FullRestoreInfo::GetInstance()->OnWindowInitialized(window);
     }
     return;
@@ -61,11 +69,16 @@
 }
 
 void FullRestoreReadHandler::OnWindowDestroyed(aura::Window* window) {
-  // TODO(crbug.com/1146900): Handle ARC app windows.
-
   DCHECK(observed_windows_.IsObservingSource(window));
   observed_windows_.RemoveObservation(window);
 
+  if (window->GetProperty(aura::client::kAppType) ==
+      static_cast<int>(ash::AppType::ARC_APP)) {
+    if (arc_read_handler_)
+      arc_read_handler_->OnWindowDestroyed(window);
+    return;
+  }
+
   int32_t restore_window_id =
       window->GetProperty(::full_restore::kRestoreWindowIdKey);
   DCHECK(SessionID::IsValidValue(restore_window_id));
@@ -175,6 +188,14 @@
 
   const int32_t restore_window_id =
       window->GetProperty(::full_restore::kRestoreWindowIdKey);
+
+  if (window->GetProperty(aura::client::kAppType) ==
+      static_cast<int>(ash::AppType::ARC_APP)) {
+    return arc_read_handler_
+               ? arc_read_handler_->GetWindowInfo(restore_window_id)
+               : nullptr;
+  }
+
   return GetWindowInfo(restore_window_id);
 }
 
diff --git a/components/full_restore/full_restore_utils.cc b/components/full_restore/full_restore_utils.cc
index 48bbd64..376c579 100644
--- a/components/full_restore/full_restore_utils.cc
+++ b/components/full_restore/full_restore_utils.cc
@@ -21,6 +21,7 @@
 DEFINE_UI_CLASS_PROPERTY_KEY(int32_t, kRestoreWindowIdKey, 0)
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kAppIdKey, nullptr)
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(int32_t, kActivationIndexKey, nullptr)
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kParentToHiddenContainerKey, false)
 
 void SaveAppLaunchInfo(const base::FilePath& profile_path,
                        std::unique_ptr<AppLaunchInfo> app_launch_info) {
diff --git a/components/full_restore/full_restore_utils.h b/components/full_restore/full_restore_utils.h
index 2e354a52..cc715cae 100644
--- a/components/full_restore/full_restore_utils.h
+++ b/components/full_restore/full_restore_utils.h
@@ -65,6 +65,11 @@
 COMPONENT_EXPORT(FULL_RESTORE)
 extern const ui::ClassProperty<int32_t*>* const kActivationIndexKey;
 
+// A property key to add the window to a hidden container, if the ARC task is
+// not created when the window is initialized.
+COMPONENT_EXPORT(FULL_RESTORE)
+extern const ui::ClassProperty<bool>* const kParentToHiddenContainerKey;
+
 // Saves the app launch parameters to the full restore file.
 COMPONENT_EXPORT(FULL_RESTORE)
 void SaveAppLaunchInfo(const base::FilePath& profile_path,
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index fc92b4c..233c8c0 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -579,6 +579,11 @@
 void MetricsWebContentsObserver::MaybeStorePageLoadTrackerForBackForwardCache(
     content::NavigationHandle* next_navigation_handle,
     std::unique_ptr<PageLoadTracker> previously_committed_load) {
+  TRACE_EVENT1("loading",
+               "MetricsWebContentsObserver::"
+               "MaybeRestorePageLoadTrackerForBackForwardCache",
+               "next_navigation", next_navigation_handle);
+
   if (!previously_committed_load)
     return;
 
@@ -603,6 +608,11 @@
 
 bool MetricsWebContentsObserver::MaybeRestorePageLoadTrackerForBackForwardCache(
     content::NavigationHandle* navigation_handle) {
+  TRACE_EVENT1("loading",
+               "MetricsWebContentsObserver::"
+               "MaybeRestorePageLoadTrackerForBackForwardCache",
+               "navigation", navigation_handle);
+
   if (!navigation_handle->IsServedFromBackForwardCache())
     return false;
 
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer.py b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
index 3626524..233d557 100755
--- a/components/policy/tools/template_writers/writers/ios_app_config_writer.py
+++ b/components/policy/tools/template_writers/writers/ios_app_config_writer.py
@@ -185,11 +185,11 @@
     element_type = _POLICY_TYPE_TO_XML_TAG[policy['type']]
     if element_type:
       attributes = {'keyName': policy['name']}
-      # Add a "future=true" attribute for future policies.
+      # Add a "<!--FUTURE POLICY-->" comment before future policies.
       if 'future_on' in policy:
         for config in policy['future_on']:
           if config['platform'] == 'ios':
-            attributes['future'] = 'true'
+            self.AddComment(self._policies, 'FUTURE POLICY')
       policy_element = self.AddElement(self._policies, element_type, attributes)
       self._WritePolicyDefaultValue(policy_element, policy)
       self._WritePolicyConstraint(policy_element, policy)
diff --git a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
index bfc9624..aadaf534 100755
--- a/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
+++ b/components/policy/tools/template_writers/writers/ios_app_config_writer_unittest.py
@@ -370,7 +370,8 @@
         'desc': 'string description'
     }])
     policy_json = self._GetTestPolicyTemplate(policy_definition)
-    expected_configuration = '''<string future="true" keyName="FuturePolicy">
+    expected_configuration = '''<!--FUTURE POLICY-->
+    <string keyName="FuturePolicy">
       <constraint nullable="true"/>
     </string>'''
     expected_presentation = '''<field keyName="FuturePolicy" type="input">
@@ -389,34 +390,6 @@
     }, 'ios_app_config')
     self.assertEquals(output.strip(), expected.strip())
 
-  def testNonFuturePolicy(self):
-    policy_definition = json.dumps([{
-        'name': 'NonFuturePolicy',
-        'type': 'string',
-        'supported_on': ['ios:80-'],
-        'caption': 'string caption',
-        'desc': 'string description'
-    }])
-    policy_json = self._GetTestPolicyTemplate(policy_definition)
-    expected_configuration = '''<string keyName="NonFuturePolicy">
-      <constraint nullable="true"/>
-    </string>'''
-    expected_presentation = '''<field keyName="NonFuturePolicy" type="input">
-      <label>
-        <language value="en-US">string caption</language>
-      </label>
-      <description>
-        <language value="en-US">string description</language>
-      </description>
-    </field>'''
-    expected = self._GetExpectedOutput('83', expected_configuration,
-                                       expected_presentation)
-    output = self.GetOutput(policy_json, {
-        '_google_chrome': '1',
-        'version': '83.0.4089.0'
-    }, 'ios_app_config')
-    self.assertEquals(output.strip(), expected.strip())
-
   def testPolicyWithGroup(self):
     policy_definition = json.dumps([{
         'name': 'PolicyInGroup',
diff --git a/components/reporting/proto/record_constants.proto b/components/reporting/proto/record_constants.proto
index 1504adc..618fe9b 100644
--- a/components/reporting/proto/record_constants.proto
+++ b/components/reporting/proto/record_constants.proto
@@ -41,6 +41,10 @@
 
   // |PRINT_JOBS| print jobs event handler
   PRINT_JOBS = 9;
+
+  // |EXTENSIONS_WORKFLOW| handler is for sending extension requests events,
+  // sent for Chrome Browser Cloud Management (CBCM).
+  EXTENSIONS_WORKFLOW = 10;
 }
 
 // |Priority| is used to determine when items from the queue should be rate
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 1f28a27..0da9ed9 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -202,7 +202,7 @@
       TRACE_DISABLED_BY_DEFAULT("loading"),
       "ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation",
       "activation_state", static_cast<int>(level), "render_frame_host",
-      base::trace_event::ToTracedValue(frame_host));
+      frame_host);
 
   throttle->WillSendActivationToRenderer();
 
diff --git a/components/ui_devtools/views/overlay_agent_unittest.cc b/components/ui_devtools/views/overlay_agent_unittest.cc
index 00c8f36..9e6494d 100644
--- a/components/ui_devtools/views/overlay_agent_unittest.cc
+++ b/components/ui_devtools/views/overlay_agent_unittest.cc
@@ -114,12 +114,14 @@
   }
 #endif
 
-  void CreateWidget(const gfx::Rect& bounds) {
+  void CreateWidget(const gfx::Rect& bounds,
+                    views::Widget::InitParams::Type type) {
     widget_ = std::make_unique<views::Widget>();
     views::Widget::InitParams params;
     params.delegate = nullptr;
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.bounds = bounds;
+    params.type = type;
 #if defined(USE_AURA)
     params.parent = GetContext();
 #endif
@@ -129,7 +131,8 @@
 
   void CreateWidget() {
     // Create a widget with default bounds.
-    return CreateWidget(gfx::Rect(0, 0, 400, 400));
+    return CreateWidget(gfx::Rect(0, 0, 400, 400),
+                        views::Widget::InitParams::Type::TYPE_WINDOW);
   }
 
   views::Widget* widget() { return widget_.get(); }
@@ -176,13 +179,14 @@
 #endif
 
 TEST_F(OverlayAgentTest, FindElementIdTargetedByPointViews) {
-  CreateWidget();
+  // Use a frameless window instead of deleting all children of |contents_view|
+  CreateWidget(gfx::Rect(0, 0, 400, 400),
+               views::Widget::InitParams::Type::TYPE_WINDOW_FRAMELESS);
 
   std::unique_ptr<protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
-  views::View* contents_view = widget()->GetContentsView();
-  contents_view->RemoveAllChildViews(true);
+  views::View* contents_view = widget()->GetRootView();
 
   views::View* child_1 = new views::View;
   views::View* child_2 = new views::View;
@@ -203,7 +207,7 @@
   child_1->SetBounds(20, 20, 100, 100);
   child_2->SetBounds(90, 50, 100, 100);
 
-  EXPECT_EQ(GetViewAtPoint(1, 1), widget()->GetContentsView());
+  EXPECT_EQ(GetViewAtPoint(1, 1), widget()->GetRootView());
   EXPECT_EQ(GetViewAtPoint(21, 21), child_1);
   EXPECT_EQ(GetViewAtPoint(170, 130), child_2);
   // At the overlap.
@@ -237,7 +241,7 @@
 
   for (const auto& test_case : kTestCases) {
     SCOPED_TRACE(testing::Message() << "Case: " << test_case.name);
-    CreateWidget(kWidgetBounds);
+    CreateWidget(kWidgetBounds, views::Widget::InitParams::Type::TYPE_WINDOW);
     // Can't just use kWidgetBounds because of Mac's menu bar.
     gfx::Vector2d widget_screen_offset =
         widget()->GetClientAreaBoundsInScreen().OffsetFromOrigin();
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index 25ff18b..d888b7c 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -17,6 +17,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/numerics/ranges.h"
 #include "base/stl_util.h"
+#include "base/timer/elapsed_timer.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/display/de_jelly.h"
@@ -528,6 +529,8 @@
   if (referenced_surfaces_.count(surface_id))
     return;
 
+  ++stats_->copied_surface_count;
+
   const CompositorFrame& frame = surface->GetActiveOrInterpolatedFrame();
 
   // If we are stretching content to fill the SurfaceDrawQuad, or if the device
@@ -1196,6 +1199,8 @@
   if (!valid_surfaces_.count(surface->surface_id()))
     return;
 
+  ++stats_->copied_surface_count;
+
   // TODO(vmpstr): provider check is a hack for unittests that don't set up a
   // resource provider.
   std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> empty_map;
@@ -1622,6 +1627,7 @@
   if (!valid_frame)
     return gfx::Rect();
   valid_surfaces_.insert(surface->surface_id());
+  ++stats_->prewalked_surface_count;
 
   CompositorRenderPass* last_pass = frame.render_pass_list.back().get();
   gfx::Rect damage_rect = DamageRectForSurface(surface, *last_pass);
@@ -1808,6 +1814,9 @@
   if (!surface->HasActiveFrame())
     return {};
 
+  // Start recording new stats for this aggregation.
+  stats_.emplace();
+
   display_trace_id_ = display_trace_id;
   expected_display_time_ = expected_display_time;
 
@@ -1836,11 +1845,14 @@
 
   DCHECK(referenced_surfaces_.empty());
 
+  base::ElapsedTimer prewalk_timer;
   PrewalkResult prewalk_result;
   gfx::Rect surfaces_damage_rect = PrewalkSurface(
       surface, /*in_moved_pixel_rp=*/false,
       /*parent_pass=*/AggregatedRenderPassId(),
       /*will_draw=*/true, /*damage_from_parent=*/gfx::Rect(), &prewalk_result);
+  stats_->prewalk_time = prewalk_timer.Elapsed();
+
   root_damage_rect_ = surfaces_damage_rect;
   // |root_damage_rect_| is used to restrict aggregating quads only if they
   // intersect this area.
@@ -1868,11 +1880,15 @@
   frame.may_contain_video = prewalk_result.may_contain_video;
   frame.content_color_usage = prewalk_result.content_color_usage;
 
+  base::ElapsedTimer copy_timer;
   CopyUndrawnSurfaces(&prewalk_result);
   referenced_surfaces_.insert(surface_id);
   CopyPasses(root_surface_frame, surface);
   referenced_surfaces_.erase(surface_id);
   DCHECK(referenced_surfaces_.empty());
+  stats_->copy_time = copy_timer.Elapsed();
+
+  RecordStatHistograms();
 
   if (dest_pass_list_->empty()) {
     ResetAfterAggregate();
@@ -1932,6 +1948,26 @@
   return frame;
 }
 
+void SurfaceAggregator::RecordStatHistograms() {
+  UMA_HISTOGRAM_COUNTS_100(
+      "Compositing.SurfaceAggregator.PrewalkedSurfaceCounted",
+      stats_->prewalked_surface_count);
+  UMA_HISTOGRAM_COUNTS_100("Compositing.SurfaceAggregator.CopiedSurfaceCount",
+                           stats_->copied_surface_count);
+
+  constexpr auto kMinTime = base::TimeDelta::FromMicroseconds(5);
+  constexpr auto kMaxTime = base::TimeDelta::FromMilliseconds(10);
+  constexpr int kTimeBuckets = 50;
+  UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+      "Compositing.SurfaceAggregator.PrewalkUs", stats_->prewalk_time, kMinTime,
+      kMaxTime, kTimeBuckets);
+  UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+      "Compositing.SurfaceAggregator.CopyUs", stats_->copy_time, kMinTime,
+      kMaxTime, kTimeBuckets);
+
+  stats_.reset();
+}
+
 void SurfaceAggregator::ResetAfterAggregate() {
   dest_pass_list_ = nullptr;
   surface_damage_rect_list_ = nullptr;
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index 00acfaf2..c5a1767 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -97,6 +97,14 @@
   struct RenderPassMapEntry;
   struct MaskFilterInfoExt;
 
+  struct AggregateStatistics {
+    int prewalked_surface_count = 0;
+    int copied_surface_count = 0;
+
+    base::TimeDelta prewalk_time;
+    base::TimeDelta copy_time;
+  };
+
   // Helper function that gets a list of render passes and returns a map from
   // render pass ids to render passes.
   static base::flat_map<CompositorRenderPassId, RenderPassMapEntry>
@@ -343,6 +351,9 @@
   // Update |last_frame_had_jelly_|, should be called once per frame.
   void SetLastFrameHadJelly(bool had_jelly);
 
+  // Records UMA histograms and resets |stats_|.
+  void RecordStatHistograms();
+
   // Resets member variables that were used during Aggregate().
   void ResetAfterAggregate();
 
@@ -385,6 +396,8 @@
   SurfaceId root_surface_id_;
   gfx::Transform root_surface_transform_;
 
+  base::Optional<AggregateStatistics> stats_;
+
   // For each Surface used in the last aggregation, gives the frame_index at
   // that time.
   SurfaceIndexMap previous_contained_surfaces_;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 86e5696..6c28015 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -51,7 +51,7 @@
 using content::IsUseZoomForDSFEnabled;
 using content::OneShotAccessibilityTreeSearch;
 using ui::AXNodeData;
-using ui::AXTreeIDRegistry;
+using ui::AXActionHandlerRegistry;
 
 static_assert(
     std::is_trivially_copyable<BrowserAccessibility::SerializedPosition>::value,
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 9aa46a8..4cba66c 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "third_party/blink/public/web/web_ax_enums.h"
 #include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_event_generator.h"
 #include "ui/accessibility/ax_node.h"
 #include "ui/accessibility/ax_node_data.h"
@@ -32,7 +33,6 @@
 #include "ui/accessibility/ax_range.h"
 #include "ui/accessibility/ax_serializable_tree.h"
 #include "ui/accessibility/ax_tree.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_manager.h"
 #include "ui/accessibility/ax_tree_observer.h"
 #include "ui/accessibility/ax_tree_update.h"
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index f03128b..14b7a5647 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -65,6 +65,7 @@
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/database/database_tracker.h"
 #include "storage/browser/file_system/external_mount_points.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 
 using base::UserDataAdapter;
 
@@ -649,4 +650,9 @@
   return nullptr;
 }
 
+void BrowserContext::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("id", unique_id_);
+}
+
 }  // namespace content
diff --git a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
index efdd06f..5f41ee78 100644
--- a/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
+++ b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/test/browser_test.h"
@@ -186,7 +187,14 @@
 
 // Tests if complete allow list set does not allow a host with a different port
 // to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, BlockDifferentPort) {
+// Flaky on Win/Mac. crbug.com/1188675
+#if defined(OS_WIN) || defined(OS_MAC)
+#define MAYBE_BlockDifferentPort DISABLED_BlockDifferentPort
+#else
+#define MAYBE_BlockDifferentPort BlockDifferentPort
+#endif
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest,
+                       MAYBE_BlockDifferentPort) {
   SetAllowList("http", kTestHost, kDisallowSubdomains);
 
   std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index b8afe0946..a88e653 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -1093,8 +1093,6 @@
 
 // Tests for feature restrictions in prerendered pages =========================
 
-// - Tests for feature-specific code methodology restrictions ==================
-
 // Tests that window.open() in a prerendering page fails.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, FeatureRestriction_WindowOpen) {
   // Navigate to an initial page.
@@ -1150,93 +1148,6 @@
   EXPECT_TRUE(base::Contains(client_urls, kPrerenderingUrl));
 }
 
-// Tests that same-origin prerendering pages have the access to Broadcast
-// Channel API.
-IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, GrantBroadcastChannel) {
-  const GURL kInitialUrl =
-      GetUrl("/prerender/restriction_broadcast_channel.html");
-  const GURL kPrerenderingUrl =
-      GetUrl("/prerender/restriction_broadcast_channel.html?prerendering");
-  const std::string initial_message =
-      "This is a message sent from the initial page";
-  const std::string prerender_message =
-      "This is a message sent from the prerendering page.";
-
-  // Navigate to an initial page.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-
-  // Make a same-origin prerendering page.
-  AddPrerender(kPrerenderingUrl);
-
-  // Send a message to the channel from the initial page.
-  EXPECT_TRUE(ExecJs(shell()->web_contents(),
-                     JsReplace("bc.postMessage($1);", initial_message)));
-
-  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
-  PrerenderHost* prerender_host =
-      registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHost();
-  ASSERT_TRUE(prerender_host);
-
-  // Check the prerendering page received the message sent by the initial page.
-  EXPECT_EQ(initial_message,
-            EvalJs(prerendered_render_frame_host, "messageReceived;"));
-
-  // Send a message to the channel from the prerendering page.
-  EXPECT_TRUE(ExecJs(prerendered_render_frame_host,
-                     JsReplace("bc.postMessage($1);", prerender_message)));
-
-  // Check the initial page received the message sent by the prerendering page.
-  EXPECT_EQ(prerender_message,
-            EvalJs(shell()->web_contents(), "messageReceived;"));
-
-  // Disconnect from the channel.
-  EXPECT_TRUE(ExecJs(shell()->web_contents(), "bc.close();"));
-  EXPECT_TRUE(ExecJs(prerendered_render_frame_host, "bc.close();"));
-}
-
-// - End: Tests for feature-specific code methodology restrictions =============
-
-// - Tests for Mojo capability control methodology restrictions ================
-
-// Tests that prerendering pages can access cookies.
-IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, CookieAccess) {
-  const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
-  const GURL kPrerenderingUrl = GetUrl("/empty.html");
-  // Navigate to an initial page.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-  // Set a cookie to the origin.
-  const std::string initial_cookie = "initial_cookie=exist";
-  const std::string prerender_cookie = "prerender_cookie=exist";
-  EvalJsResult result =
-      EvalJs(shell()->web_contents(),
-             "document.cookie='" + initial_cookie + "; path=/'");
-  EXPECT_TRUE(result.error.empty()) << result.error;
-
-  // Make a prerendered page.
-  AddPrerender(kPrerenderingUrl);
-  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
-  PrerenderHost* prerender_host =
-      registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHost();
-
-  // Verify the prerendered page can read the cookie.
-  EXPECT_EQ(initial_cookie,
-            EvalJs(prerendered_render_frame_host, "document.cookie"));
-
-  // Verify the prerendered page can update cookies.
-  EvalJsResult prerender_result =
-      EvalJs(prerendered_render_frame_host,
-             "document.cookie='" + prerender_cookie + "; path=/'");
-  EXPECT_TRUE(prerender_result.error.empty()) << prerender_result.error;
-  // Read the updated cookie from the initial page.
-  EXPECT_EQ(initial_cookie + "; " + prerender_cookie,
-            EvalJs(shell()->web_contents(), "document.cookie"));
-}
-
 // Test that a cross-site navigation from prerendering browser context will
 // cancel prerendering.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest,
@@ -1354,89 +1265,6 @@
   EXPECT_EQ(LifecycleState::kActive, rfh_d->lifecycle_state());
 }
 
-// Tests that prerendering pages can access local storage.
-IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, LocalStorageAccess) {
-  const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
-  const GURL kPrerenderingUrl = GetUrl("/empty.html");
-  // Navigate to an initial page.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-  // Add an item to local storage from the initial page.
-  const std::string key = "set_by";
-  const std::string initial_value = "initial";
-  const std::string prerender_value = "prerender";
-  EvalJsResult result = EvalJs(
-      shell()->web_contents(),
-      JsReplace("window.localStorage.setItem($1, $2)", key, initial_value));
-  EXPECT_TRUE(result.error.empty()) << result.error;
-
-  // Make a prerendered page.
-  AddPrerender(kPrerenderingUrl);
-  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
-  PrerenderHost* prerender_host =
-      registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerendered_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHost();
-
-  // Verify the prerendered page can read the item that the initial page wrote.
-  EXPECT_EQ(initial_value,
-            EvalJs(prerendered_render_frame_host,
-                   JsReplace("window.localStorage.getItem($1)", key)));
-
-  // Verify the prerendered page can update local storage.
-  EvalJsResult prerender_result = EvalJs(
-      prerendered_render_frame_host,
-      JsReplace("window.localStorage.setItem($1, $2)", key, prerender_value));
-  EXPECT_TRUE(prerender_result.error.empty()) << prerender_result.error;
-  // Read the updated item value from the initial page.
-  EXPECT_EQ(prerender_value,
-            EvalJs(shell()->web_contents(),
-                   JsReplace("window.localStorage.getItem($1)", key)));
-}
-
-// Tests that prerendering pages can access Indexed Database.
-IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, IndexedDBAccess) {
-  const GURL kInitialUrl = GetUrl("/prerender/restriction_indexeddb.html");
-  const GURL kPrerenderingUrl =
-      GetUrl("/prerender/restriction_indexeddb.html?prerendering");
-
-  // Navigate to an initial page.
-  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
-
-  const std::string initial_key = "initial";
-  const std::string initial_value = initial_key + "_set";
-  const std::string prerender_key = "prerender";
-  const std::string prerender_value = prerender_key + "_set";
-
-  // Write an object to Indexed Database.
-  EXPECT_EQ(true,
-            EvalJs(shell()->web_contents(),
-                   JsReplace("addData($1, $2);", initial_key, initial_value)));
-
-  // Make a prerendered page.
-  AddPrerender(kPrerenderingUrl);
-  PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
-  PrerenderHost* prerender_host =
-      registry.FindHostByUrlForTesting(kPrerenderingUrl);
-  ASSERT_TRUE(prerender_host);
-  RenderFrameHostImpl* prerender_render_frame_host =
-      prerender_host->GetPrerenderedMainFrameHost();
-
-  // Verify the prerendered page can read the object that the initial page
-  // wrote.
-  EXPECT_EQ(initial_value, EvalJs(prerender_render_frame_host,
-                                  JsReplace("readData($1);", initial_key)));
-
-  // The prerendered page writes another object to Indexed Database.
-  EXPECT_EQ(true, EvalJs(prerender_render_frame_host,
-                         JsReplace("addData($1, $2);", prerender_key,
-                                   prerender_value)));
-
-  // Read the added object from the initial page.
-  EXPECT_EQ(prerender_value, EvalJs(shell()->web_contents(),
-                                    JsReplace("readData($1);", prerender_key)));
-}
-
 // Tests that prerendering is gated behind CSP:prefetch-src
 // TODO(https://crbug.com/1185679) This is currently not the case. Fix this.
 IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, CSPPrefetchSrc) {
@@ -1680,7 +1508,6 @@
   EXPECT_EQ(registry.FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
 }
 
-// - End: Tests for Mojo capability control methodology restrictions ===========
 
 // Tests that prerendering pages cannot access the Async Clipboard API because
 // they are not focused.
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc
index c529c0ce..ce581f52 100644
--- a/content/browser/prerender/prerender_host.cc
+++ b/content/browser/prerender/prerender_host.cc
@@ -419,8 +419,7 @@
     RenderFrameHostImpl& old_render_frame_host,
     NavigationRequest& navigation_request) {
   TRACE_EVENT1("navigation", "PrerenderHost::ActivatePrerenderedContents",
-               "render_frame_host",
-               base::trace_event::ToTracedValue(&old_render_frame_host));
+               "render_frame_host", old_render_frame_host);
 
   DCHECK(is_ready_for_activation_);
   is_ready_for_activation_ = false;
diff --git a/content/browser/prerender/prerender_host_registry.cc b/content/browser/prerender/prerender_host_registry.cc
index 8051e91..dd2e557 100644
--- a/content/browser/prerender/prerender_host_registry.cc
+++ b/content/browser/prerender/prerender_host_registry.cc
@@ -109,7 +109,7 @@
   RenderFrameHostImpl* render_frame_host = frame_tree_node.current_frame_host();
   TRACE_EVENT2("navigation", "PrerenderHostRegistry::ReserveHostToActivate",
                "navigation_url", navigation_url.spec(), "render_frame_host",
-               base::trace_event::ToTracedValue(render_frame_host));
+               render_frame_host);
 
   // Disallow activation when the navigation is for prerendering.
   if (frame_tree_node.frame_tree()->is_prerendering())
diff --git a/content/browser/renderer_host/clipboard_host_impl_browsertest.cc b/content/browser/renderer_host/clipboard_host_impl_browsertest.cc
index 8c82042..0e6248ca 100644
--- a/content/browser/renderer_host/clipboard_host_impl_browsertest.cc
+++ b/content/browser/renderer_host/clipboard_host_impl_browsertest.cc
@@ -108,7 +108,13 @@
   CopyPasteFiles({File{"small.jpg", "image/jpeg"}});
 }
 
-IN_PROC_BROWSER_TEST_F(ClipboardHostImplBrowserTest, Empty) {
+// Flaky on linux-ozone-rel. crbug.com/1189398
+#if defined(USE_OZONE)
+#define MAYBE_Empty DISABLED_Empty
+#else
+#define MAYBE_Empty Empty
+#endif
+IN_PROC_BROWSER_TEST_F(ClipboardHostImplBrowserTest, MAYBE_Empty) {
   CopyPasteFiles({});
 }
 
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc
index 0f296d0..06fbd9f 100644
--- a/content/browser/renderer_host/frame_tree_node.cc
+++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -811,4 +811,10 @@
   popup_creator_origin_ = popup_creator_origin;
 }
 
+void FrameTreeNode::WriteIntoTracedValue(perfetto::TracedValue context) const {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("id", frame_tree_node_id());
+  dict.Add("is_main_frame", IsMainFrame());
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h
index 2792e18..d1136ff 100644
--- a/content/browser/renderer_host/frame_tree_node.h
+++ b/content/browser/renderer_host/frame_tree_node.h
@@ -449,6 +449,9 @@
   // tree.
   void SetFrameTree(FrameTree& frame_tree);
 
+  // Write a representation of this object into a trace.
+  void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(SitePerProcessPermissionsPolicyBrowserTest,
                            ContainerPolicyDynamic);
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 8f84654..2f67097 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -3983,9 +3983,9 @@
 void NavigationControllerImpl::UpdateStateForFrame(
     RenderFrameHostImpl* rfhi,
     const blink::PageState& page_state) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "NavigationControllerImpl::UpdateStateForFrame",
-      "render_frame_host", base::trace_event::ToTracedValue(rfhi));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "NavigationControllerImpl::UpdateStateForFrame",
+                        "render_frame_host", rfhi);
   // The state update affects the last NavigationEntry associated with the given
   // |render_frame_host|. This may not be the last committed NavigationEntry (as
   // in the case of an UpdateState from a frame being swapped out). We track
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index a4f8f71..aa83053 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -1190,8 +1190,7 @@
   }
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("navigation", "NavigationRequest",
-                                    navigation_id_, "navigation_request",
-                                    base::trace_event::ToTracedValue(this));
+                                    navigation_id_, "navigation_request", this);
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("navigation", "Initializing",
                                     navigation_id_);
 
@@ -5201,28 +5200,29 @@
   return origin;
 }
 
-void NavigationRequest::AsValueInto(
-    base::trace_event::TracedValue* traced_value) {
-  traced_value->SetPointer("this", this);
-  traced_value->SetInteger("navigation_id", navigation_id_);
-  traced_value->SetInteger("frame_tree_node",
-                           frame_tree_node_->frame_tree_node_id());
-  traced_value->SetString("url", common_params_->url.possibly_invalid_spec());
-  traced_value->SetBoolean("browser_initiated", browser_initiated_);
-  traced_value->SetBoolean("from_begin_navigation", from_begin_navigation_);
-  traced_value->SetBoolean("is_for_commit", is_for_commit_);
-  traced_value->SetInteger("reload_type", static_cast<int>(reload_type_));
-  traced_value->SetInteger("navigation_type",
-                           static_cast<int>(common_params_->navigation_type));
-  traced_value->SetInteger("state", static_cast<int>(state_));
+void NavigationRequest::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("navigation_id", navigation_id_);
+  dict.Add("has_committed", HasCommitted());
+  dict.Add("is_error_page", IsErrorPage());
+  dict.Add("net_error", net_error_);
+  dict.Add("url", common_params_->url);
+  dict.Add("frame_tree_node", frame_tree_node_);
+  dict.Add("browser_initiated", browser_initiated_);
+  dict.Add("from_begin_navigation", from_begin_navigation_);
+  dict.Add("is_for_commit", is_for_commit_);
+  dict.Add("reload_type", reload_type_);
+  dict.Add("state", state_);
+  dict.Add("navigation_type", common_params_->navigation_type);
 
   if (IsServedFromBackForwardCache()) {
-    traced_value->SetBoolean("bf cached", true);
-    rfh_restored_from_back_forward_cache_->AsValueInto(traced_value);
+    dict.Add("served_from_bfcache", true);
+    dict.Add("rfh_restored_from_bfcache",
+             rfh_restored_from_back_forward_cache_);
   }
 
   if (state_ >= WILL_PROCESS_RESPONSE)
-    GetRenderFrameHost()->AsValueInto(traced_value);
+    dict.Add("render_frame_host", GetRenderFrameHost());
 }
 
 void NavigationRequest::RenderProcessBlockedStateChanged(bool blocked) {
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index fab5bea..0af823c 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -60,6 +60,7 @@
 #include "third_party/blink/public/common/navigation/impression.h"
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/loader/mixed_content.mojom-forward.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/scoped_java_ref.h"
@@ -345,6 +346,7 @@
   void SetSilentlyIgnoreErrors() override;
   network::mojom::WebSandboxFlags SandboxFlagsToCommit() override;
   bool IsWaitingToCommit() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 
   // Called on the UI thread by the Navigator to start the navigation.
   // The NavigationRequest can be deleted while BeginNavigation() is called.
@@ -734,10 +736,6 @@
   // renamed GetOriginToCommit() and the value pushed to blink.
   url::Origin GetOriginForURLLoaderFactory();
 
-  // Add information about this NavigationRequest to |traced_value| for
-  // tracing purposes.
-  void AsValueInto(base::trace_event::TracedValue* traced_value);
-
   // If this navigation fails with net::ERR_BLOCKED_BY_CLIENT, act as if it were
   // cancelled by the user and do not commit an error page.
   void SetSilentlyIgnoreBlockedByClient() {
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 492c0767..90d84b32 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -248,9 +248,9 @@
 #include "third_party/blink/public/mojom/timing/resource_timing.mojom.h"
 #include "third_party/blink/public/mojom/usb/web_usb_service.mojom.h"
 #include "third_party/blink/public/mojom/webauthn/virtual_authenticator.mojom.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_common.h"
 #include "ui/accessibility/ax_tree.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_update.h"
 #include "ui/events/event_constants.h"
 #include "ui/gfx/geometry/quad_f.h"
@@ -1032,8 +1032,8 @@
 RenderFrameHostImpl* RenderFrameHostImpl::FromAXTreeID(
     ui::AXTreeID ax_tree_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  ui::AXTreeIDRegistry::FrameID frame_id =
-      ui::AXTreeIDRegistry::GetInstance()->GetFrameID(ax_tree_id);
+  ui::AXActionHandlerRegistry::FrameID frame_id =
+      ui::AXActionHandlerRegistry::GetInstance()->GetFrameID(ax_tree_id);
   return RenderFrameHostImpl::FromID(frame_id.first, frame_id.second);
 }
 
@@ -3207,6 +3207,11 @@
 void RenderFrameHostImpl::DidCommitSameDocumentNavigation(
     mojom::DidCommitProvisionalLoadParamsPtr params,
     mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params) {
+  TRACE_EVENT2("navigation",
+               "RenderFrameHostImpl::DidCommitSameDocumentNavigation",
+               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
+               params->url.possibly_invalid_spec());
+
   ScopedActiveURL scoped_active_url(params->url,
                                     frame_tree()->root()->current_origin());
   ScopedCommitStateResetter commit_state_resetter(this);
@@ -3219,16 +3224,18 @@
   // See https://crbug.com/805705 and https://crbug.com/930132.
   // TODO(ahemery): Investigate to see if this can be removed when the
   // NavigationClient interface is implemented.
+  //
   // If this is called when the frame is in BackForwardCache, evict the frame
   // to avoid ignoring the renderer-initiated navigation, which the frame
   // might not expect.
-  if (IsInactiveAndDisallowActivation())
+  //
+  // If this is called when the frame is in Prerendering, do not cancel
+  // Prerendering as prerendered frames can be navigated, including
+  // same-document navigations like push/replaceState.
+  if (lifecycle_state() != LifecycleState::kPrerendering &&
+      IsInactiveAndDisallowActivation()) {
     return;
-
-  TRACE_EVENT2("navigation",
-               "RenderFrameHostImpl::DidCommitSameDocumentNavigation",
-               "frame_tree_node", frame_tree_node_->frame_tree_node_id(), "url",
-               params->url.possibly_invalid_spec());
+  }
 
   // Check if the navigation matches a stored same-document NavigationRequest.
   // In that case it is browser-initiated.
@@ -3907,27 +3914,16 @@
       this, std::move(info));
 }
 
-void RenderFrameHostImpl::AsValueInto(
-    base::trace_event::TracedValue* traced_value) {
-  traced_value->SetPointer("this", this);
-  traced_value->SetInteger("process_id", GetProcess()->GetID());
-  traced_value->SetInteger("render_frame_id", GetRoutingID());
-  traced_value->SetString("lifecycle_state",
-                          LifecycleStateToString(lifecycle_state_));
-  traced_value->SetString(
-      "origin", base::trace_event::ValueToString(GetLastCommittedOrigin()));
-  traced_value->SetString(
-      "url", base::trace_event::ValueToString(GetLastCommittedURL()));
-  traced_value->SetInteger("frame_tree_node_id",
-                           frame_tree_node_->frame_tree_node_id());
-  traced_value->SetInteger("site_instance_id", GetSiteInstance()->GetId());
-  traced_value->SetInteger("browsing_instance_id",
-                           GetSiteInstance()->GetBrowsingInstanceId());
-  traced_value->BeginDictionary("parent");
-  if (GetParent()) {
-    GetParent()->AsValueInto(traced_value);
-  }
-  traced_value->EndDictionary();
+void RenderFrameHostImpl::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("process", GetProcess());
+  dict.Add("routing_id", GetRoutingID());
+  dict.Add("lifecycle_state", LifecycleStateToString(lifecycle_state_));
+  dict.Add("origin", GetLastCommittedOrigin());
+  dict.Add("url", GetLastCommittedURL());
+  dict.Add("frame_tree_node_id", frame_tree_node_->frame_tree_node_id());
+  dict.Add("site_instance", GetSiteInstance());
+  dict.Add("parent", GetParent());
 }
 
 StoragePartition* RenderFrameHostImpl::GetStoragePartition() {
@@ -4457,9 +4453,8 @@
 
 void RenderFrameHostImpl::GoToEntryAtOffset(int32_t offset,
                                             bool has_user_gesture) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "RenderFrameHostImpl::GoToEntryAtOffset", "render_frame_host",
-      base::trace_event::ToTracedValue(this), "offset", offset);
+  OPTIONAL_TRACE_EVENT2("content", "RenderFrameHostImpl::GoToEntryAtOffset",
+                        "render_frame_host", this, "offset", offset);
 
   // Non-user initiated navigations coming from the renderer should be ignored
   // if there is an ongoing browser-initiated navigation.
@@ -5194,8 +5189,7 @@
 
 void RenderFrameHostImpl::UpdateState(const blink::PageState& state) {
   OPTIONAL_TRACE_EVENT1("content", "RenderFrameHostImpl::UpdateState",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(this));
+                        "render_frame_host", this);
   // TODO(creis): Verify the state's ISN matches the last committed FNE.
 
   // Without this check, the renderer can trick the browser into using
@@ -5773,9 +5767,8 @@
 void RenderFrameHostImpl::SubresourceResponseStarted(
     const GURL& url,
     net::CertStatus cert_status) {
-  OPTIONAL_TRACE_EVENT1("content",
-                        "RenderFrameHostImpl::SubresourceResponseStarted",
-                        "url", base::trace_event::ValueToString(url));
+  OPTIONAL_TRACE_EVENT1(
+      "content", "RenderFrameHostImpl::SubresourceResponseStarted", "url", url);
   frame_tree_->controller().ssl_manager()->DidStartResourceResponse(
       url, cert_status);
   delegate_->SubresourceResponseStarted();
@@ -9203,56 +9196,6 @@
   same_document_navigation_requests_.erase(navigation_token);
 }
 
-std::unique_ptr<base::trace_event::TracedValue>
-RenderFrameHostImpl::CommitAsTracedValue(
-    const mojom::DidCommitProvisionalLoadParams& params) const {
-  auto value = std::make_unique<base::trace_event::TracedValue>();
-
-  // TODO(nasko): Move the process lock into RenderProcessHost.
-  value->SetString(
-      "process lock",
-      ChildProcessSecurityPolicyImpl::GetInstance()
-          ->GetProcessLock(agent_scheduling_group_.GetProcess()->GetID())
-          .ToString());
-
-  value->SetInteger("item_sequence_number", params.item_sequence_number);
-  value->SetInteger("document_sequence_number",
-                    params.document_sequence_number);
-  value->SetString("url", params.url.spec());
-  if (!params.base_url.is_empty()) {
-    value->SetString("base_url", params.base_url.possibly_invalid_spec());
-  }
-  value->SetInteger("transition", params.transition);
-  value->BeginDictionary("referrer");
-  value->SetString("url", params.referrer->url.spec());
-  value->SetInteger("policy", static_cast<int>(params.referrer->policy));
-  value->EndDictionary();
-  value->SetBoolean("should_update_history", params.should_update_history);
-  value->SetString("contents_mime_type", params.contents_mime_type);
-
-  value->SetBoolean("intended_as_new_entry", params.intended_as_new_entry);
-  value->SetBoolean("did_create_new_entry", params.did_create_new_entry);
-  value->SetBoolean("should_replace_current_entry",
-                    params.should_replace_current_entry);
-  value->SetString("method", params.method);
-  value->SetInteger("post_id", params.post_id);
-  value->SetInteger("http_status_code", params.http_status_code);
-  value->SetBoolean("url_is_unreachable", params.url_is_unreachable);
-  value->SetBoolean("is_overriding_user_agent",
-                    params.is_overriding_user_agent);
-  value->SetBoolean("history_list_was_cleared",
-                    params.history_list_was_cleared);
-  value->SetString("origin", params.origin.GetDebugString());
-  value->SetBoolean("has_potentially_trustworthy_unique_origin",
-                    params.has_potentially_trustworthy_unique_origin);
-  value->SetInteger("request_id", params.request_id);
-  value->SetString("navigation_token", params.navigation_token.ToString());
-  if (params.embedding_token)
-    value->SetString("embedding_token", params.embedding_token->ToString());
-
-  return value;
-}
-
 void RenderFrameHostImpl::MaybeGenerateCrashReport(
     base::TerminationStatus status,
     int exit_code) {
@@ -9410,8 +9353,7 @@
   RenderProcessHost* process = GetProcess();
 
   TRACE_EVENT2("navigation", "RenderFrameHostImpl::DidCommitProvisionalLoad",
-               "rfh", base::trace_event::ToTracedValue(this), "params",
-               CommitAsTracedValue(*params));
+               "rfh", this, "params", params);
 
   // If we're waiting for a cross-site beforeunload completion callback from
   // this renderer and we receive a Navigate message from the main frame, then
@@ -10427,8 +10369,8 @@
 
 void RenderFrameHostImpl::SetLifecycleState(LifecycleState state) {
   TRACE_EVENT2("content", "RenderFrameHostImpl::SetLifecycleState",
-               "render_frame_host", base::trace_event::ToTracedValue(this),
-               "new_state", LifecycleStateToString(state));
+               "render_frame_host", this, "new_state",
+               LifecycleStateToString(state));
 #if DCHECK_IS_ON()
   static const base::NoDestructor<StateTransitions<LifecycleState>>
       allowed_transitions(
@@ -10633,11 +10575,12 @@
   embedding_token_ = embedding_token;
 
   // The AXTreeID of a frame is backed by its embedding token, so we need to
-  // update its AXTreeID, as well as the associated mapping in AXTreeIDRegistry.
+  // update its AXTreeID, as well as the associated mapping in
+  // AXActionHandlerRegistry.
   ui::AXTreeID ax_tree_id = ui::AXTreeID::FromToken(embedding_token);
   SetAXTreeID(ax_tree_id);
-  ui::AXTreeIDRegistry::GetInstance()->SetFrameIDForAXTreeID(
-      ui::AXTreeIDRegistry::FrameID(GetProcess()->GetID(), routing_id_),
+  ui::AXActionHandlerRegistry::GetInstance()->SetFrameIDForAXTreeID(
+      ui::AXActionHandlerRegistry::FrameID(GetProcess()->GetID(), routing_id_),
       ax_tree_id);
 
   // Also important to notify the delegate so that the relevant observers can
@@ -10681,10 +10624,9 @@
 
 void RenderFrameHostImpl::OnDidRunInsecureContent(const GURL& security_origin,
                                                   const GURL& target_url) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "RenderFrameHostImpl::DidRunInsecureContent",
-      "security_origin", base::trace_event::ValueToString(security_origin),
-      "target_url", base::trace_event::ValueToString(target_url));
+  OPTIONAL_TRACE_EVENT2("content", "RenderFrameHostImpl::DidRunInsecureContent",
+                        "security_origin", security_origin, "target_url",
+                        target_url);
 
   // TODO(nick, estark): Should we call FilterURL using this frame's process on
   // these parameters? |target_url| seems unused, except for a log message. And
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 6ea24fc..d3098e21 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -419,7 +419,7 @@
   StoragePartition* GetStoragePartition() override;
   BrowserContext* GetBrowserContext() override;
   void ReportInspectorIssue(blink::mojom::InspectorIssueInfoPtr info) override;
-  void AsValueInto(base::trace_event::TracedValue* traced_value) override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 
   // Determines if a clipboard paste using |data| of type |data_type| is allowed
   // in this renderer frame.  The implementation delegates to
@@ -2599,11 +2599,6 @@
       bool should_replace_current_entry,
       blink::mojom::CommitResult result);
 
-  // Creates a TracedValue object containing the details of a committed
-  // navigation, so it can be logged with the tracing system.
-  std::unique_ptr<base::trace_event::TracedValue> CommitAsTracedValue(
-      const mojom::DidCommitProvisionalLoadParams& params) const;
-
   // Creates URLLoaderFactory objects for |isolated_world_origins|.
   //
   // Properties of the factories (e.g. their client security state) are either
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 4ad8b786..c9253e4 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1576,12 +1576,11 @@
       instance_weak_factory_(base::in_place, this),
       shutdown_exit_code_(-1) {
   CHECK(!browser_context->ShutdownStarted());
-  TRACE_EVENT2("shutdown", "RenderProcessHostImpl", "render_process_host",
-               static_cast<void*>(this), "id", GetID());
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
-      "shutdown", "Browser.RenderProcessHostImpl", static_cast<void*>(this),
-      "render_process_host", static_cast<void*>(this), "browser_context",
-      static_cast<void*>(browser_context_));
+  TRACE_EVENT2("shutdown", "RenderProcessHostImpl", "render_process_host", this,
+               "id", GetID());
+  TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("shutdown", "Browser.RenderProcessHostImpl",
+                                    this, "render_process_host", this,
+                                    "browser_context", browser_context_);
   widget_helper_ = new RenderWidgetHelper();
 
   ChildProcessSecurityPolicyImpl::GetInstance()->Add(GetID(), browser_context);
@@ -1681,7 +1680,7 @@
 
 RenderProcessHostImpl::~RenderProcessHostImpl() {
   TRACE_EVENT2("shutdown", "~RenderProcessHostImpl", "render_process_host",
-               static_cast<void*>(this), "id", GetID());
+               this, "id", GetID());
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 #ifndef NDEBUG
   DCHECK(is_self_deleted_)
@@ -1709,13 +1708,11 @@
     RemoveNetworkServicePluginExceptions(GetID());
 
   TRACE_EVENT_NESTABLE_ASYNC_END2("shutdown", "Cleanup in progress", this,
-                                  "render_process_host",
-                                  static_cast<void*>(this), "browser_context",
-                                  static_cast<void*>(browser_context_));
+                                  "render_process_host", this,
+                                  "browser_context", browser_context_);
   TRACE_EVENT_NESTABLE_ASYNC_END2("shutdown", "Browser.RenderProcessHostImpl",
-                                  this, "render_process_host",
-                                  static_cast<void*>(this), "browser_context",
-                                  static_cast<void*>(browser_context_));
+                                  this, "render_process_host", this,
+                                  "browser_context", browser_context_);
 }
 
 bool RenderProcessHostImpl::Init() {
@@ -2203,6 +2200,15 @@
 }
 #endif
 
+void RenderProcessHostImpl::WriteIntoTracedValue(
+    perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("id", GetID());
+  dict.Add("process_lock", ChildProcessSecurityPolicyImpl::GetInstance()
+                               ->GetProcessLock(GetID())
+                               .ToString());
+}
+
 void RenderProcessHostImpl::RegisterMojoInterfaces() {
   auto registry = std::make_unique<service_manager::BinderRegistry>();
 
@@ -2651,8 +2657,8 @@
 
 void RenderProcessHostImpl::DisableKeepAliveRefCount() {
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::DisableKeepAliveRefCount",
-               "browser_context", static_cast<void*>(browser_context_),
-               "render_process_host", static_cast<void*>(this));
+               "browser_context", browser_context_, "render_process_host",
+               this);
 
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -2729,8 +2735,7 @@
 void RenderProcessHostImpl::AddRoute(int32_t routing_id,
                                      IPC::Listener* listener) {
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::AddRoute",
-               "render_process_host", static_cast<void*>(this), "routing_id",
-               routing_id);
+               "render_process_host", this, "routing_id", routing_id);
   CHECK(!listeners_.Lookup(routing_id))
       << "Found Routing ID Conflict: " << routing_id;
   listeners_.AddWithID(listener, routing_id);
@@ -2738,8 +2743,7 @@
 
 void RenderProcessHostImpl::RemoveRoute(int32_t routing_id) {
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::RemoveRoute",
-               "render_process_host", static_cast<void*>(this), "routing_id",
-               routing_id);
+               "render_process_host", this, "routing_id", routing_id);
   DCHECK(listeners_.Lookup(routing_id) != nullptr);
   listeners_.Remove(routing_id);
   Cleanup();
@@ -3603,7 +3607,7 @@
 
 void RenderProcessHostImpl::Cleanup() {
   TRACE_EVENT1("shutdown", "RenderProcessHostImpl::Cleanup",
-               "render_process_host", static_cast<void*>(this));
+               "render_process_host", this);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   // Keep the one renderer thread around forever in single process mode.
   if (run_renderer_in_process())
@@ -3618,7 +3622,7 @@
     TRACE_EVENT1(
         "shutdown",
         "RenderProcessHostImpl::Cleanup : within_process_died_observer",
-        "render_process_host", static_cast<void*>(this));
+        "render_process_host", this);
     delayed_cleanup_needed_ = true;
     return;
   }
@@ -3635,23 +3639,22 @@
   // ourselves.
   if (!listeners_.IsEmpty()) {
     TRACE_EVENT2("shutdown", "RenderProcessHostImpl::Cleanup : Has listeners.",
-                 "render_process_host", static_cast<void*>(this),
-                 "listener_count", listeners_.size());
+                 "render_process_host", this, "listener_count",
+                 listeners_.size());
     return;
   } else if (keep_alive_ref_count_ != 0) {
     TRACE_EVENT2("shutdown",
                  "RenderProcessHostImpl::Cleanup : Have keep_alive_ref.",
-                 "render_process_host", static_cast<void*>(this),
-                 "keep_alive_ref_count_", keep_alive_ref_count_);
+                 "render_process_host", this, "keep_alive_ref_count_",
+                 keep_alive_ref_count_);
     return;
   }
 
   TRACE_EVENT1("shutdown", "RenderProcessHostImpl::Cleanup : Starting cleanup.",
-               "render_process_host", static_cast<void*>(this));
+               "render_process_host", this);
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("shutdown", "Cleanup in progress", this,
-                                    "render_process_host",
-                                    static_cast<void*>(this), "browser_context",
-                                    static_cast<void*>(browser_context_));
+                                    "render_process_host", this,
+                                    "browser_context", browser_context_);
 
   if (is_initialized_) {
     GetIOThreadTaskRunner({})->PostTask(
@@ -3818,8 +3821,7 @@
 // static
 void RenderProcessHostImpl::RegisterHost(int host_id, RenderProcessHost* host) {
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::RegisterHost",
-               "render_process_host", static_cast<void*>(host), "host_id",
-               host_id);
+               "render_process_host", host, "host_id", host_id);
   GetAllHosts().AddWithID(host, host_id);
 }
 
@@ -3827,8 +3829,7 @@
 void RenderProcessHostImpl::UnregisterHost(int host_id) {
   RenderProcessHost* host = GetAllHosts().Lookup(host_id);
   TRACE_EVENT2("shutdown", "RenderProcessHostImpl::UnregisterHost",
-               "render_process_host", static_cast<void*>(host), "host_id",
-               host_id);
+               "render_process_host", host, "host_id", host_id);
 
   if (!host)
     return;
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 7457db7..6bc63978 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -87,6 +87,7 @@
 #include "third_party/blink/public/mojom/plugins/plugin_registry.mojom-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h"
 #include "third_party/blink/public/mojom/webdatabase/web_database.mojom.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
 #if defined(OS_ANDROID)
@@ -270,6 +271,7 @@
   void ForceCrash() override;
   void CleanupNetworkServicePluginExceptionsUponDestruction() override;
   std::string GetInfoForBrowserContextDestructionCrashReporting() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
   void DumpProfilingData(base::OnceClosure callback) override;
 #endif
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 3423fb2..00644aa 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -86,6 +86,7 @@
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/web_preferences/web_preferences.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/device_form_factor.h"
@@ -973,4 +974,10 @@
   will_send_renderer_preferences_callback_for_testing_ = callback;
 }
 
+void RenderViewHostImpl::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("routing_id", GetRoutingID());
+  dict.Add("process", GetProcess());
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 98e8d29..b9b5b09 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -40,6 +40,7 @@
 #include "third_party/blink/public/mojom/page/page.mojom.h"
 #include "third_party/blink/public/web/web_ax_enums.h"
 #include "third_party/blink/public/web/web_console_message.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gl/gpu_preference.h"
@@ -132,6 +133,7 @@
       blink::mojom::PluginActionType action) override;
   RenderViewHostDelegate* GetDelegate() override;
   bool IsRenderViewLive() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 
   void SendWebPreferencesToRenderer();
   void SendRendererPreferencesToRenderer(
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 5b3d5b68..eee53fb 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1796,6 +1796,11 @@
   return input_router_->AllowedTouchAction();
 }
 
+void RenderWidgetHostImpl::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("routing_id", GetRoutingID());
+}
+
 void RenderWidgetHostImpl::DragTargetDragEnter(
     const DropData& drop_data,
     const gfx::PointF& client_pt,
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index f60c84a..668051f 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -250,6 +250,7 @@
   void GetScreenInfo(blink::ScreenInfo* result) override;
   float GetDeviceScaleFactor() override;
   base::Optional<cc::TouchAction> GetAllowedTouchAction() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
   // |drop_data| must have been filtered. The embedder should call
   // FilterDropData before passing the drop data to RWHI.
   void DragTargetDragEnter(const DropData& drop_data,
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index 4329bc2c..b9d5c2bb 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -36,7 +36,7 @@
 #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
 #include "third_party/blink/public/mojom/page/record_content_to_visible_time_request.mojom-forward.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/base/ime/mojom/text_input_state.mojom-forward.h"
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 2dc48824..b6b3f77 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -34,6 +34,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/origin.h"
 #include "url/url_constants.h"
 
@@ -377,6 +378,14 @@
       browser_context, site_url());
 }
 
+void SiteInfo::WriteIntoTracedValue(perfetto::TracedValue context) const {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("site_url", site_url());
+  dict.Add("process_lock_url", process_lock_url());
+  dict.Add("is_origin_keyed", is_origin_keyed_);
+  dict.Add("is_guest", is_guest_);
+}
+
 bool SiteInfo::is_error_page() const {
   return !is_guest_ && site_url_ == GetErrorPageSiteAndLockURL();
 }
@@ -1715,4 +1724,13 @@
     GetContentClient()->browser()->PersistIsolatedOrigin(context, site_origin);
 }
 
+void SiteInstanceImpl::WriteIntoTracedValue(perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("id", GetId());
+  dict.Add("browsing_instance_id", GetBrowsingInstanceId());
+  dict.Add("is_default", IsDefaultSiteInstance());
+  dict.Add("site_info", site_info_);
+  dict.Add("active_frame_count", active_frame_count_);
+}
+
 }  // namespace content
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index a52a337a..6d38572 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -16,6 +16,7 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition_config.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -269,6 +270,9 @@
   StoragePartitionConfig GetStoragePartitionConfig(
       BrowserContext* browser_context) const;
 
+  // Write a representation of this object into a trace.
+  void WriteIntoTracedValue(perfetto::TracedValue context) const;
+
  private:
   static auto MakeTie(const SiteInfo& site_info);
 
@@ -424,6 +428,7 @@
   bool IsSameSiteWithURL(const GURL& url) override;
   bool IsGuest() override;
   SiteInstanceProcessAssignment GetLastProcessAssignmentOutcome() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 
   // This is called every time a renderer process is assigned to a SiteInstance
   // and is used by the content embedder for collecting metrics.
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index 60e361e..32d252c1 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -45,7 +45,7 @@
 class SmsBrowserTest : public ContentBrowserTest {
  public:
   using Entry = ukm::builders::SMSReceiver;
-  using FailureType = SmsFetcher::FailureType;
+  using FailureType = SmsFetchFailureType;
 
   SmsBrowserTest() = default;
   ~SmsBrowserTest() override = default;
diff --git a/content/browser/sms/sms_fetcher_impl.cc b/content/browser/sms/sms_fetcher_impl.cc
index 2a6b6ea..aae1ddbe 100644
--- a/content/browser/sms/sms_fetcher_impl.cc
+++ b/content/browser/sms/sms_fetcher_impl.cc
@@ -96,9 +96,14 @@
 }
 
 void SmsFetcherImpl::OnRemote(base::Optional<OriginList> origin_list,
-                              base::Optional<std::string> one_time_code) {
+                              base::Optional<std::string> one_time_code,
+                              base::Optional<FailureType> failure_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  if (failure_type) {
+    OnFailure(failure_type.value());
+    return;
+  }
   if (!origin_list || !one_time_code)
     return;
 
@@ -112,7 +117,7 @@
   return Notify(origin_list, one_time_code, consent_requirement);
 }
 
-bool SmsFetcherImpl::OnFailure(SmsFetcher::FailureType failure_type) {
+bool SmsFetcherImpl::OnFailure(FailureType failure_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return subscribers_.NotifyFailure(failure_type);
 }
diff --git a/content/browser/sms/sms_fetcher_impl.h b/content/browser/sms/sms_fetcher_impl.h
index 0930ae4..862bf1e 100644
--- a/content/browser/sms/sms_fetcher_impl.h
+++ b/content/browser/sms/sms_fetcher_impl.h
@@ -29,6 +29,8 @@
                                       public base::SupportsUserData::Data,
                                       public SmsProvider::Observer {
  public:
+  using FailureType = SmsFetchFailureType;
+
   SmsFetcherImpl(BrowserContext* context, SmsProvider* provider);
   ~SmsFetcherImpl() override;
 
@@ -48,13 +50,14 @@
   bool OnReceive(const OriginList& origin_list,
                  const std::string& one_time_code,
                  UserConsent) override;
-  bool OnFailure(SmsFetcher::FailureType failure_type) override;
+  bool OnFailure(FailureType failure_type) override;
 
   bool HasSubscribers() override;
 
  private:
   void OnRemote(base::Optional<OriginList>,
-                base::Optional<std::string> one_time_code);
+                base::Optional<std::string> one_time_code,
+                base::Optional<FailureType> failure_type);
 
   bool Notify(const OriginList& origin_list,
               const std::string& one_time_code,
diff --git a/content/browser/sms/sms_fetcher_impl_unittest.cc b/content/browser/sms/sms_fetcher_impl_unittest.cc
index 2476365..caee12d 100644
--- a/content/browser/sms/sms_fetcher_impl_unittest.cc
+++ b/content/browser/sms/sms_fetcher_impl_unittest.cc
@@ -22,6 +22,7 @@
 namespace content {
 
 using UserConsent = SmsFetcher::UserConsent;
+using FailureType = SmsFetchFailureType;
 
 namespace {
 
@@ -34,7 +35,8 @@
                void(BrowserContext*,
                     const url::Origin&,
                     base::OnceCallback<void(base::Optional<OriginList>,
-                                            base::Optional<std::string>)>));
+                                            base::Optional<std::string>,
+                                            base::Optional<FailureType>)>));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockContentBrowserClient);
@@ -49,7 +51,7 @@
                void(const OriginList&,
                     const std::string& one_time_code,
                     UserConsent));
-  MOCK_METHOD1(OnFailure, void(SmsFetcher::FailureType failure_type));
+  MOCK_METHOD1(OnFailure, void(FailureType failure_type));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSubscriber);
@@ -109,9 +111,11 @@
       .WillOnce(Invoke(
           [&](BrowserContext*, const url::Origin&,
               base::OnceCallback<void(base::Optional<OriginList>,
-                                      base::Optional<std::string>)> callback) {
+                                      base::Optional<std::string>,
+                                      base::Optional<FailureType>)> callback) {
             std::move(callback).Run(
-                OriginList{url::Origin::Create(GURL("https://a.com"))}, "123");
+                OriginList{url::Origin::Create(GURL("https://a.com"))}, "123",
+                base::nullopt);
           }));
 
   EXPECT_CALL(subscriber, OnReceive(_, "123", _));
@@ -128,8 +132,10 @@
       .WillOnce(Invoke(
           [&](BrowserContext*, const url::Origin&,
               base::OnceCallback<void(base::Optional<OriginList>,
-                                      base::Optional<std::string>)> callback) {
-            std::move(callback).Run(base::nullopt, base::nullopt);
+                                      base::Optional<std::string>,
+                                      base::Optional<FailureType>)> callback) {
+            std::move(callback).Run(base::nullopt, base::nullopt,
+                                    base::nullopt);
           }));
 
   EXPECT_CALL(subscriber, OnReceive(_, _, _)).Times(0);
@@ -146,9 +152,11 @@
       .WillOnce(Invoke(
           [&](BrowserContext*, const url::Origin&,
               base::OnceCallback<void(base::Optional<OriginList>,
-                                      base::Optional<std::string>)> callback) {
+                                      base::Optional<std::string>,
+                                      base::Optional<FailureType>)> callback) {
             std::move(callback).Run(
-                OriginList{url::Origin::Create(GURL("b.com"))}, "123");
+                OriginList{url::Origin::Create(GURL("b.com"))}, "123",
+                base::nullopt);
           }));
 
   EXPECT_CALL(subscriber, OnReceive(_, _, _)).Times(0);
@@ -168,9 +176,11 @@
       .WillOnce(Invoke(
           [&](BrowserContext*, const url::Origin&,
               base::OnceCallback<void(base::Optional<OriginList>,
-                                      base::Optional<std::string>)> callback) {
+                                      base::Optional<std::string>,
+                                      base::Optional<FailureType>)> callback) {
             std::move(callback).Run(
-                OriginList{url::Origin::Create(GURL("https://a.com"))}, "123");
+                OriginList{url::Origin::Create(GURL("https://a.com"))}, "123",
+                base::nullopt);
           }));
 
   EXPECT_CALL(*provider(), Retrieve(_, _)).WillOnce(Invoke([&]() {
@@ -234,10 +244,29 @@
   fetcher1.Subscribe(OriginList{kOrigin}, &subscriber1, main_rfh());
   fetcher2.Subscribe(OriginList{kOrigin}, &subscriber2, main_rfh());
 
-  EXPECT_CALL(subscriber1, OnFailure(SmsFetcher::FailureType::kPromptTimeout));
-  EXPECT_CALL(subscriber2, OnFailure(SmsFetcher::FailureType::kPromptTimeout))
-      .Times(0);
-  provider()->NotifyFailure(SmsFetcher::FailureType::kPromptTimeout);
+  EXPECT_CALL(subscriber1, OnFailure(FailureType::kPromptTimeout));
+  EXPECT_CALL(subscriber2, OnFailure(FailureType::kPromptTimeout)).Times(0);
+  provider()->NotifyFailure(FailureType::kPromptTimeout);
+}
+
+TEST_F(SmsFetcherImplTest, FetchRemoteSmsFailed) {
+  StrictMock<MockSubscriber> subscriber;
+  SmsFetcherImpl fetcher(nullptr, provider());
+
+  EXPECT_CALL(*client(), FetchRemoteSms(_, _, _))
+      .WillOnce(Invoke(
+          [&](BrowserContext*, const url::Origin&,
+              base::OnceCallback<void(base::Optional<OriginList>,
+                                      base::Optional<std::string>,
+                                      base::Optional<FailureType>)> callback) {
+            std::move(callback).Run(base::nullopt, base::nullopt,
+                                    FailureType::kPromptCancelled);
+          }));
+
+  EXPECT_CALL(subscriber, OnFailure(_));
+
+  fetcher.Subscribe(OriginList{url::Origin::Create(GURL("https://a.com"))},
+                    &subscriber, main_rfh());
 }
 
 }  // namespace content
diff --git a/content/browser/sms/sms_provider.h b/content/browser/sms/sms_provider.h
index 7ef147e..4f069f4 100644
--- a/content/browser/sms/sms_provider.h
+++ b/content/browser/sms/sms_provider.h
@@ -31,7 +31,7 @@
 // inject custom providers.
 class CONTENT_EXPORT SmsProvider {
  public:
-  using FailureType = SmsFetcher::FailureType;
+  using FailureType = SmsFetchFailureType;
   using SmsParsingStatus = SmsParser::SmsParsingStatus;
   using UserConsent = SmsFetcher::UserConsent;
 
@@ -42,7 +42,7 @@
     virtual bool OnReceive(const OriginList&,
                            const std::string& one_time_code,
                            UserConsent) = 0;
-    virtual bool OnFailure(SmsFetcher::FailureType failure_type) = 0;
+    virtual bool OnFailure(FailureType failure_type) = 0;
     virtual void NotifyParsingFailure(SmsParser::SmsParsingStatus) {}
   };
 
diff --git a/content/browser/sms/sms_provider_gms.cc b/content/browser/sms/sms_provider_gms.cc
index 92355dd..f9981eb 100644
--- a/content/browser/sms/sms_provider_gms.cc
+++ b/content/browser/sms/sms_provider_gms.cc
@@ -81,15 +81,15 @@
 }
 
 void SmsProviderGms::OnTimeout(JNIEnv* env) {
-  NotifyFailure(SmsFetcher::FailureType::kPromptTimeout);
+  NotifyFailure(SmsFetchFailureType::kPromptTimeout);
 }
 
 void SmsProviderGms::OnCancel(JNIEnv* env) {
-  NotifyFailure(SmsFetcher::FailureType::kPromptCancelled);
+  NotifyFailure(SmsFetchFailureType::kPromptCancelled);
 }
 
 void SmsProviderGms::OnNotAvailable(JNIEnv* env) {
-  NotifyFailure(SmsFetcher::FailureType::kBackendNotAvailable);
+  NotifyFailure(SmsFetchFailureType::kBackendNotAvailable);
 }
 
 void SmsProviderGms::SetClientAndWindowForTesting(
diff --git a/content/browser/sms/sms_provider_gms_unittest.cc b/content/browser/sms/sms_provider_gms_unittest.cc
index e5b1186..aa2acf6 100644
--- a/content/browser/sms/sms_provider_gms_unittest.cc
+++ b/content/browser/sms/sms_provider_gms_unittest.cc
@@ -40,7 +40,7 @@
                bool(const OriginList&,
                     const std::string& one_time_code,
                     SmsFetcher::UserConsent));
-  MOCK_METHOD1(OnFailure, bool(SmsFetcher::FailureType));
+  MOCK_METHOD1(OnFailure, bool(SmsFetchFailureType));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockObserver);
@@ -307,7 +307,7 @@
 TEST_F(SmsProviderGmsAutoTest, FailureOnRemoteRequestShouldNotFallback) {
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kRemote);
@@ -318,7 +318,7 @@
 
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kRemote);
@@ -329,7 +329,7 @@
 
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kRemote);
@@ -344,7 +344,7 @@
 TEST_F(SmsProviderGmsVerificationTest, ExpectedFailuresShouldCancel) {
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kLocal);
@@ -355,7 +355,7 @@
 
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kLocal);
@@ -366,7 +366,7 @@
 
   {
     EXPECT_CALL(*observer(),
-                OnFailure(SmsFetcher::FailureType::kBackendNotAvailable))
+                OnFailure(SmsFetchFailureType::kBackendNotAvailable))
         .Times(1);
 
     provider()->Retrieve(main_rfh(), SmsFetchType::kLocal);
diff --git a/content/browser/sms/sms_queue.h b/content/browser/sms/sms_queue.h
index ed5a317..ca86c17 100644
--- a/content/browser/sms/sms_queue.h
+++ b/content/browser/sms/sms_queue.h
@@ -20,7 +20,7 @@
   SmsQueue();
   ~SmsQueue();
 
-  using FailureType = SmsFetcher::FailureType;
+  using FailureType = SmsFetchFailureType;
   using Subscriber = SmsFetcher::Subscriber;
 
   void Push(const OriginList& origin_list, Subscriber* subscriber);
diff --git a/content/browser/sms/webotp_service.cc b/content/browser/sms/webotp_service.cc
index e93e1eb9..a59c3fc 100644
--- a/content/browser/sms/webotp_service.cc
+++ b/content/browser/sms/webotp_service.cc
@@ -233,6 +233,7 @@
     case FailureType::kPromptTimeout:
     case FailureType::kPromptCancelled:
     case FailureType::kBackendNotAvailable:
+    case FailureType::kNoFailure:
       NOTREACHED();
       break;
   }
diff --git a/content/browser/sms/webotp_service.h b/content/browser/sms/webotp_service.h
index 0e56b24..d99fd9e 100644
--- a/content/browser/sms/webotp_service.h
+++ b/content/browser/sms/webotp_service.h
@@ -50,7 +50,7 @@
                 mojo::PendingReceiver<blink::mojom::WebOTPService>);
   ~WebOTPService() override;
 
-  using FailureType = SmsFetcher::FailureType;
+  using FailureType = SmsFetchFailureType;
   using SmsParsingStatus = SmsParser::SmsParsingStatus;
   using UserConsent = SmsFetcher::UserConsent;
 
diff --git a/content/browser/sms/webotp_service_unittest.cc b/content/browser/sms/webotp_service_unittest.cc
index 8a6a8bc..25d3db9 100644
--- a/content/browser/sms/webotp_service_unittest.cc
+++ b/content/browser/sms/webotp_service_unittest.cc
@@ -60,7 +60,7 @@
 class RenderFrameHost;
 
 using Entry = ukm::builders::SMSReceiver;
-using FailureType = SmsFetcher::FailureType;
+using FailureType = SmsFetchFailureType;
 using UserConsent = SmsFetcher::UserConsent;
 
 namespace {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 54a40fff..6aa1ca63 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -566,7 +566,7 @@
 WebContents* WebContents::FromRenderViewHost(RenderViewHost* rvh) {
   OPTIONAL_TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("content.verbose"),
                         "WebContents::FromRenderViewHost", "render_view_host",
-                        static_cast<void*>(rvh));
+                        rvh);
   if (!rvh)
     return nullptr;
   return rvh->GetDelegate()->GetAsWebContents();
@@ -575,7 +575,7 @@
 WebContents* WebContents::FromRenderFrameHost(RenderFrameHost* rfh) {
   OPTIONAL_TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("content.verbose"),
                         "WebContents::FromRenderFrameHost", "render_frame_host",
-                        base::trace_event::ToTracedValue(rfh));
+                        rfh);
   if (!rfh)
     return nullptr;
   if (!rfh->IsCurrent() && base::FeatureList::IsEnabled(
@@ -1008,7 +1008,7 @@
     const WebContents::CreateParams& params,
     RenderFrameHostImpl* opener_rfh) {
   OPTIONAL_TRACE_EVENT1("browser", "WebContentsImpl::CreateWithOpener",
-                        "opener", base::trace_event::ToTracedValue(opener_rfh));
+                        "opener", opener_rfh);
   FrameTreeNode* opener = nullptr;
   if (opener_rfh)
     opener = opener_rfh->frame_tree_node();
@@ -1137,8 +1137,7 @@
 bool WebContentsImpl::OnMessageReceived(RenderViewHostImpl* render_view_host,
                                         const IPC::Message& message) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnMessageReceived",
-                        "render_view_host",
-                        static_cast<void*>(render_view_host));
+                        "render_view_host", render_view_host);
   for (auto& observer : observers_.observer_list()) {
     // TODO(nick, creis): https://crbug.com/758026: Replace all uses of this
     // variant of OnMessageReceived with the version that takes a
@@ -1153,8 +1152,7 @@
 bool WebContentsImpl::OnMessageReceived(RenderFrameHostImpl* render_frame_host,
                                         const IPC::Message& message) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnMessageReceived",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
 
   for (auto& observer : observers_.observer_list()) {
     if (observer.OnMessageReceived(message, render_frame_host))
@@ -1564,9 +1562,7 @@
     RenderFrameHost* rfh,
     const base::Optional<GURL>& manifest_url) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::NotifyManifestUrlChanged",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(rfh), "manifest_url",
-                        base::trace_event::ValueToString(manifest_url));
+                        "render_frame_host", rfh, "manifest_url", manifest_url);
   observers_.NotifyObservers(&WebContentsObserver::DidUpdateWebManifestURL, rfh,
                              manifest_url);
 }
@@ -2681,7 +2677,7 @@
 void WebContentsImpl::OnCookiesAccessed(NavigationHandle* navigation,
                                         const CookieAccessDetails& details) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnCookiesAccessed",
-                        "navigation_handle", static_cast<void*>(navigation));
+                        "navigation_handle", navigation);
   // Use a variable to select between overloads.
   void (WebContentsObserver::*func)(NavigationHandle*,
                                     const CookieAccessDetails&) =
@@ -2692,8 +2688,7 @@
 void WebContentsImpl::OnCookiesAccessed(RenderFrameHostImpl* rfh,
                                         const CookieAccessDetails& details) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnCookiesAccessed",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(rfh));
+                        "render_frame_host", rfh);
   // Use a variable to select between overloads.
   void (WebContentsObserver::*func)(RenderFrameHost*,
                                     const CookieAccessDetails&) =
@@ -2937,8 +2932,7 @@
 
 void WebContentsImpl::LostCapture(RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::LostCapture",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   if (!RenderViewHostImpl::From(render_widget_host))
     return;
 
@@ -2956,8 +2950,8 @@
     RenderWidgetHostImpl* render_widget_host,
     float ratio) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SetTopControlsShownRatio",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host), "ratio", ratio);
+                        "render_widget_host", render_widget_host, "ratio",
+                        ratio);
   if (!delegate_)
     return;
 
@@ -2979,16 +2973,14 @@
 void WebContentsImpl::RenderWidgetCreated(
     RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderWidgetCreated",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   created_widgets_.insert(render_widget_host);
 }
 
 void WebContentsImpl::RenderWidgetDeleted(
     RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderWidgetDeleted",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   // Note that |is_being_destroyed_| can be true at this point as
   // ~WebContentsImpl() calls RFHM::ClearRFHsPendingShutdown(), which might lead
   // us here.
@@ -3007,9 +2999,8 @@
     RenderWidgetHostImpl* render_widget_host,
     bool width_changed) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RenderWidgetWasResized",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host), "width_changed",
-                        width_changed);
+                        "render_widget_host", render_widget_host,
+                        "width_changed", width_changed);
   RenderFrameHostImpl* rfh = GetMainFrame();
   if (!rfh || render_widget_host != rfh->GetRenderWidgetHost())
     return;
@@ -3229,8 +3220,8 @@
     bool is_fullscreen,
     blink::mojom::FullscreenOptionsPtr options) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::FullscreenStateChanged",
-                        "render_frame_host", static_cast<void*>(rfh),
-                        "is_fullscreen", is_fullscreen);
+                        "render_frame_host", rfh, "is_fullscreen",
+                        is_fullscreen);
 
   if (is_fullscreen) {
     if (options.is_null()) {
@@ -3416,9 +3407,9 @@
     bool user_gesture,
     bool last_unlocked_by_target,
     bool privileged) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::RequestToLockMouse", "render_widget_host",
-      static_cast<void*>(render_widget_host), "privileged", privileged);
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RequestToLockMouse",
+                        "render_widget_host", render_widget_host, "privileged",
+                        privileged);
   for (WebContentsImpl* current = this; current;
        current = current->GetOuterWebContents()) {
     if (current->mouse_lock_widget_) {
@@ -3460,8 +3451,7 @@
 
 void WebContentsImpl::LostMouseLock(RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::LostMouseLock",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   CHECK(mouse_lock_widget_);
 
   if (mouse_lock_widget_->delegate()->GetAsWebContents() != this)
@@ -3498,9 +3488,9 @@
 bool WebContentsImpl::RequestKeyboardLock(
     RenderWidgetHostImpl* render_widget_host,
     bool esc_key_locked) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::RequestKeyboardLock", "render_widget_host",
-      static_cast<void*>(render_widget_host), "esc_key_locked", esc_key_locked);
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RequestKeyboardLock",
+                        "render_widget_host", render_widget_host,
+                        "esc_key_locked", esc_key_locked);
   DCHECK(render_widget_host);
   if (render_widget_host->delegate()->GetAsWebContents() != this) {
     NOTREACHED();
@@ -3523,8 +3513,7 @@
 void WebContentsImpl::CancelKeyboardLock(
     RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::CancelKeyboardLockRequest",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   if (!keyboard_lock_widget_ || render_widget_host != keyboard_lock_widget_)
     return;
 
@@ -3566,8 +3555,7 @@
     bool has_user_gesture,
     SessionStorageNamespace* session_storage_namespace) {
   TRACE_EVENT2("browser,content,navigation", "WebContentsImpl::CreateNewWindow",
-               "opener", base::trace_event::ToTracedValue(opener), "params",
-               params);
+               "opener", opener, "params", params);
   DCHECK(opener);
 
   int render_process_id = opener->GetProcess()->GetID();
@@ -3754,9 +3742,8 @@
         blink_popup_widget_host,
     mojo::PendingAssociatedReceiver<blink::mojom::WidgetHost> blink_widget_host,
     mojo::PendingAssociatedRemote<blink::mojom::Widget> blink_widget) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::CreateNewPopupWidget", "params",
-      base::trace_event::TracedValue::Build({{"route_id", route_id}}));
+  OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::CreateNewPopupWidget",
+                        "route_id", route_id);
   RenderProcessHost* process = agent_scheduling_group.GetProcess();
   // A message to create a new widget can only come from an active process for
   // this WebContentsImpl instance. If any other process sends the request,
@@ -3793,8 +3780,7 @@
                                         const gfx::Rect& initial_rect,
                                         bool user_gesture) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::ShowCreatedWindow",
-                        "opener", base::trace_event::ToTracedValue(opener),
-                        "main_frame_widget_route_id",
+                        "opener", opener, "main_frame_widget_route_id",
                         main_frame_widget_route_id);
   // This method is the renderer requesting an existing top level window to
   // show a new top level window that the renderer created. Each top level
@@ -3980,10 +3966,10 @@
     RenderFrameHostImpl* render_frame_host,
     const url::Origin& security_origin,
     blink::mojom::MediaStreamType type) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::CheckMediaAccessPermission",
-      "render_frame_host", static_cast<void*>(render_frame_host),
-      "security_origin", security_origin.Serialize());
+  OPTIONAL_TRACE_EVENT2("content",
+                        "WebContentsImpl::CheckMediaAccessPermission",
+                        "render_frame_host", render_frame_host,
+                        "security_origin", security_origin);
 
   DCHECK(type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE ||
          type == blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
@@ -4269,8 +4255,7 @@
     RenderWidgetHostImpl* render_widget_host,
     const gfx::Size& new_size) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::ResizeDueToAutoResize",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   if (render_widget_host != GetRenderViewHost()->GetWidget())
     return;
 
@@ -4279,8 +4264,7 @@
 }
 
 WebContents* WebContentsImpl::OpenURL(const OpenURLParams& params) {
-  TRACE_EVENT1("content", "WebContentsImpl::OpenURL", "url",
-               base::trace_event::ValueToString(params.url));
+  TRACE_EVENT1("content", "WebContentsImpl::OpenURL", "url", params.url);
 #if DCHECK_IS_ON()
   DCHECK(params.Valid());
 #endif
@@ -4575,8 +4559,7 @@
                                const base::FilePath& dir_path,
                                SavePageType save_type) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SavePage", "main_file",
-                        base::trace_event::ValueToString(main_file), "dir_path",
-                        base::trace_event::ValueToString(dir_path));
+                        main_file, "dir_path", dir_path);
   // Stop the page from navigating.
   Stop();
 
@@ -4600,8 +4583,7 @@
   DCHECK(rfh);
 
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SaveFrameWithHeaders",
-                        "url", base::trace_event::ValueToString(url), "headers",
-                        headers);
+                        "url", url, "headers", headers);
   // Check and see if the guest can handle this.
   if (delegate_) {
     WebContents* guest_web_contents = nullptr;
@@ -4712,8 +4694,7 @@
     base::OnceCallback<void(uint64_t /* file_size */,
                             data_decoder::mojom::WebBundlerError)> callback) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::GenerateWebBundle",
-                        "file_path",
-                        base::trace_event::ValueToString(file_path));
+                        "file_path", file_path);
   SaveAsWebBundleJob::Start(this, file_path, std::move(callback));
 }
 
@@ -4795,24 +4776,23 @@
 void WebContentsImpl::NotifyWebContentsFocused(
     RenderWidgetHost* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::NotifyWebContentsFocused",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   observers_.NotifyObservers(&WebContentsObserver::OnWebContentsFocused,
                              render_widget_host);
 }
 
 void WebContentsImpl::NotifyWebContentsLostFocus(
     RenderWidgetHost* render_widget_host) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::NotifyWebContentsLostFocus",
-      "render_widget_host", static_cast<void*>(render_widget_host));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::NotifyWebContentsLostFocus",
+                        "render_widget_host", render_widget_host);
   observers_.NotifyObservers(&WebContentsObserver::OnWebContentsLostFocus,
                              render_widget_host);
 }
 
 void WebContentsImpl::SystemDragEnded(RenderWidgetHost* source_rwh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::SystemDragEnded",
-                        "render_widget_host", static_cast<void*>(source_rwh));
+                        "render_widget_host", source_rwh);
   if (source_rwh)
     source_rwh->DragSourceSystemDragEnded();
 }
@@ -4946,7 +4926,7 @@
     bool bypass_cache,
     WebContents::ImageDownloadCallback callback) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DownloadImage", "url",
-                        base::trace_event::ValueToString(url));
+                        url);
   return DownloadImageInFrame(GlobalFrameRoutingId(), url, is_favicon,
                               preferred_size, max_bitmap_size, bypass_cache,
                               std::move(callback));
@@ -5136,7 +5116,7 @@
 
 void WebContentsImpl::DidStartNavigation(NavigationHandle* navigation_handle) {
   TRACE_EVENT1("navigation", "WebContentsImpl::DidStartNavigation",
-               "navigation_handle", static_cast<void*>(navigation_handle));
+               "navigation_handle", navigation_handle);
   if (navigation_handle->IsInMainFrame())
     favicon_urls_.clear();
 
@@ -5164,7 +5144,7 @@
 void WebContentsImpl::DidRedirectNavigation(
     NavigationHandle* navigation_handle) {
   TRACE_EVENT1("navigation", "WebContentsImpl::DidRedirectNavigation",
-               "navigation_handle", static_cast<void*>(navigation_handle));
+               "navigation_handle", navigation_handle);
   observers_.NotifyObservers(&WebContentsObserver::DidRedirectNavigation,
                              navigation_handle);
   // Notify accessibility if this is a reload. This has to called on the
@@ -5183,7 +5163,7 @@
 void WebContentsImpl::ReadyToCommitNavigation(
     NavigationHandle* navigation_handle) {
   TRACE_EVENT1("navigation", "WebContentsImpl::ReadyToCommitNavigation",
-               "navigation_handle", static_cast<void*>(navigation_handle));
+               "navigation_handle", navigation_handle);
   observers_.NotifyObservers(&WebContentsObserver::ReadyToCommitNavigation,
                              navigation_handle);
   // If any domains are blocked from accessing 3D APIs because they may
@@ -5239,7 +5219,7 @@
 
 void WebContentsImpl::DidFinishNavigation(NavigationHandle* navigation_handle) {
   TRACE_EVENT1("navigation", "WebContentsImpl::DidFinishNavigation",
-               "navigation_handle", static_cast<void*>(navigation_handle));
+               "navigation_handle", navigation_handle);
 
   observers_.NotifyObservers(&WebContentsObserver::DidFinishNavigation,
                              navigation_handle);
@@ -5326,9 +5306,7 @@
     const GURL& url,
     int error_code) {
   TRACE_EVENT2("content,navigation", "WebContentsImpl::DidFailLoadWithError",
-               "render_frame_host",
-               base::trace_event::ToTracedValue(render_frame_host), "url",
-               base::trace_event::ValueToString(url));
+               "render_frame_host", render_frame_host, "url", url);
   observers_.NotifyObservers(&WebContentsObserver::DidFailLoad,
                              render_frame_host, url, error_code);
 }
@@ -5378,9 +5356,9 @@
     RenderFrameHostImpl* render_frame_host,
     const LoadCommittedDetails& details,
     const mojom::DidCommitProvisionalLoadParams& params) {
-  OPTIONAL_TRACE_EVENT1(
-      "content,navigation", "WebContentsImpl::DidNavigateMainFramePostCommit",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host));
+  OPTIONAL_TRACE_EVENT1("content,navigation",
+                        "WebContentsImpl::DidNavigateMainFramePostCommit",
+                        "render_frame_host", render_frame_host);
   if (details.is_navigation_to_different_page()) {
     // Clear the status bubble. This is a workaround for a bug where WebKit
     // doesn't let us know that the cursor left an element during a
@@ -5415,9 +5393,9 @@
     RenderFrameHostImpl* render_frame_host,
     const LoadCommittedDetails& details,
     const mojom::DidCommitProvisionalLoadParams& params) {
-  OPTIONAL_TRACE_EVENT1(
-      "content,navigation", "WebContentsImpl::DidNavigateAnyFramePostCommit",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host));
+  OPTIONAL_TRACE_EVENT1("content,navigation",
+                        "WebContentsImpl::DidNavigateAnyFramePostCommit",
+                        "render_frame_host", render_frame_host);
 
   // If we navigate off the page, close all JavaScript dialogs.
   if (!details.is_same_document)
@@ -5440,7 +5418,7 @@
 
 void WebContentsImpl::OnThemeColorChanged(RenderViewHostImpl* source) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnThemeColorChanged",
-                        "render_view_host", static_cast<void*>(source));
+                        "render_view_host", source);
   if (source->did_first_visually_non_empty_paint() &&
       last_sent_theme_color_ != source->theme_color()) {
     observers_.NotifyObservers(&WebContentsObserver::DidChangeThemeColor);
@@ -5462,10 +5440,9 @@
     const std::string& http_method,
     const std::string& mime_type,
     network::mojom::RequestDestination request_destination) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::DidLoadResourceFromMemoryCache",
-      "render_frame_host", base::trace_event::ToTracedValue(source), "url",
-      base::trace_event::ValueToString(url));
+  OPTIONAL_TRACE_EVENT2("content",
+                        "WebContentsImpl::DidLoadResourceFromMemoryCache",
+                        "render_frame_host", source, "url", url);
   observers_.NotifyObservers(
       &WebContentsObserver::DidLoadResourceFromMemoryCache, url, mime_type,
       request_destination);
@@ -5489,9 +5466,9 @@
 }
 
 void WebContentsImpl::PassiveInsecureContentFound(const GURL& resource_url) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::PassiveInsecureContentFound", "resource_url",
-      base::trace_event::ValueToString(resource_url));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::PassiveInsecureContentFound",
+                        "resource_url", resource_url);
   if (delegate_) {
     delegate_->PassiveInsecureContentFound(resource_url);
   }
@@ -5513,8 +5490,7 @@
 
 void WebContentsImpl::ViewSource(RenderFrameHostImpl* frame) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::ViewSource",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(frame));
+                        "render_frame_host", frame);
   DCHECK_EQ(this, WebContents::FromRenderFrameHost(frame));
 
   // Don't do anything if there is no |delegate_| that could accept and show the
@@ -5608,12 +5584,9 @@
     RenderFrameHostImpl* render_frame_host,
     const GlobalRequestID& request_id,
     blink::mojom::ResourceLoadInfoPtr resource_load_info) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::ResourceLoadComplete", "render_frame_host",
-      base::trace_event::ToTracedValue(render_frame_host), "request_id",
-      base::trace_event::TracedValue::Build(
-          {{"child_id", request_id.child_id},
-           {"request_id", request_id.request_id}}));
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::ResourceLoadComplete",
+                        "render_frame_host", render_frame_host, "request_id",
+                        request_id);
   const blink::mojom::ResourceLoadInfo& resource_load_info_ref =
       *resource_load_info;
   observers_.NotifyObservers(&WebContentsObserver::ResourceLoadComplete,
@@ -5666,8 +5639,7 @@
     int document_cookie,
     RenderFrameHostImpl* subframe_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::PrintCrossProcessSubframe",
-                        "subframe",
-                        base::trace_event::ToTracedValue(subframe_host));
+                        "subframe", subframe_host);
   auto* outer_contents = GetOuterWebContents();
   if (outer_contents) {
     // When an extension or app page is printed, the content should be
@@ -5692,7 +5664,7 @@
     RenderFrameHostImpl* render_frame_host) {
   OPTIONAL_TRACE_EVENT1(
       "content", "WebContentsImpl::CapturePaintPreviewOfCrossProcessSubframe",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host));
+      "render_frame_host", render_frame_host);
   if (!delegate_)
     return;
   delegate_->CapturePaintPreviewOfSubframe(this, rect, guid, render_frame_host);
@@ -5707,8 +5679,7 @@
 
 void WebContentsImpl::DOMContentLoaded(RenderFrameHostImpl* render_frame_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DOMContentLoaded",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   observers_.NotifyObservers(&WebContentsObserver::DOMContentLoaded,
                              render_frame_host);
 }
@@ -5716,9 +5687,7 @@
 void WebContentsImpl::OnDidFinishLoad(RenderFrameHostImpl* render_frame_host,
                                       const GURL& url) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnDidFinishLoad",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
-                        "url", base::trace_event::ValueToString(url));
+                        "render_frame_host", render_frame_host, "url", url);
   GURL validated_url(url);
   render_frame_host->GetProcess()->FilterURL(false, &validated_url);
 
@@ -5742,9 +5711,8 @@
 void WebContentsImpl::OnPageScaleFactorChanged(RenderFrameHostImpl* source,
                                                float page_scale_factor) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnPageScaleFactorChanged",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source),
-                        "page_scale_factor", page_scale_factor);
+                        "render_frame_host", source, "page_scale_factor",
+                        page_scale_factor);
 #if !defined(OS_ANDROID)
   // While page scale factor is used on mobile, this PageScaleFactorIsOne logic
   // is only needed on desktop.
@@ -5770,9 +5738,9 @@
 void WebContentsImpl::OnTextAutosizerPageInfoChanged(
     RenderFrameHostImpl* source,
     blink::mojom::TextAutosizerPageInfoPtr page_info) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::OnTextAutosizerPageInfoChanged",
-      "render_frame_host", base::trace_event::ToTracedValue(source));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::OnTextAutosizerPageInfoChanged",
+                        "render_frame_host", source);
   // Keep a copy of |page_info| in case we create a new RenderView before
   // the next update.
   text_autosizer_page_info_.main_frame_width = page_info->main_frame_width;
@@ -5798,10 +5766,9 @@
     RenderFrameHost* render_frame_host,
     scoped_refptr<FileChooserImpl::FileSelectListenerImpl> listener,
     const base::FilePath& directory_path) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::EnumerateDirectory", "render_frame_host",
-      base::trace_event::ToTracedValue(render_frame_host), "directory_path",
-      base::trace_event::ValueToString(directory_path));
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::EnumerateDirectory",
+                        "render_frame_host", render_frame_host,
+                        "directory_path", directory_path);
   // Any explicit focusing of another window while this WebContents is in
   // fullscreen can be used to confuse the user, so drop fullscreen.
   base::ScopedClosureRunner fullscreen_block = ForSecurityDropFullscreen();
@@ -5818,9 +5785,7 @@
                                               const GURL& url,
                                               bool user_gesture) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RegisterProtocolHandler",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source), "protocol",
-                        protocol);
+                        "render_frame_host", source, "protocol", protocol);
   // TODO(nick): Do we need to apply FilterURL to |url|?
   if (!delegate_)
     return;
@@ -5843,9 +5808,7 @@
                                                 const GURL& url,
                                                 bool user_gesture) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::UnregisterProtocolHandler",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source), "protocol",
-                        protocol);
+                        "render_frame_host", source, "protocol", protocol);
   // TODO(nick): Do we need to apply FilterURL to |url|?
   if (!delegate_)
     return;
@@ -5893,17 +5856,16 @@
     const std::vector<GURL>& resources_list,
     blink::mojom::ReferrerPtr referrer,
     const std::vector<blink::mojom::SavableSubframePtr>& subframes) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::SavableResourceLinksResponse",
-      "render_frame_host", base::trace_event::ToTracedValue(source));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::SavableResourceLinksResponse",
+                        "render_frame_host", source);
   save_package_->SavableResourceLinksResponse(source, resources_list,
                                               std::move(referrer), subframes);
 }
 
 void WebContentsImpl::SavableResourceLinksError(RenderFrameHostImpl* source) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::SavableResourceLinksError",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   save_package_->SavableResourceLinksError(source);
 }
 
@@ -5912,9 +5874,7 @@
     const GURL& scope,
     AllowServiceWorkerResult allowed) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnServiceWorkerAccessed",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
-                        "scope", base::trace_event::ValueToString(scope));
+                        "render_frame_host", render_frame_host, "scope", scope);
   // Use a variable to select between overloads.
   void (WebContentsObserver::*func)(RenderFrameHost*, const GURL&,
                                     AllowServiceWorkerResult) =
@@ -5927,8 +5887,7 @@
     const GURL& scope,
     AllowServiceWorkerResult allowed) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnServiceWorkerAccessed",
-                        "navigation_handle", static_cast<void*>(navigation),
-                        "scope", base::trace_event::ValueToString(scope));
+                        "navigation_handle", navigation, "scope", scope);
   // Use a variable to select between overloads.
   void (WebContentsObserver::*func)(NavigationHandle*, const GURL&,
                                     AllowServiceWorkerResult) =
@@ -5965,8 +5924,7 @@
 void WebContentsImpl::OnPepperInstanceCreated(RenderFrameHostImpl* source,
                                               int32_t pp_instance) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperInstanceCreated",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   observers_.NotifyObservers(&WebContentsObserver::PepperInstanceCreated);
   pepper_playback_observer_->PepperInstanceCreated(source, pp_instance);
 }
@@ -5974,8 +5932,7 @@
 void WebContentsImpl::OnPepperInstanceDeleted(RenderFrameHostImpl* source,
                                               int32_t pp_instance) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperInstanceDeleted",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   observers_.NotifyObservers(&WebContentsObserver::PepperInstanceDeleted);
   pepper_playback_observer_->PepperInstanceDeleted(source, pp_instance);
 }
@@ -5985,8 +5942,7 @@
                                          const base::FilePath& path,
                                          bool is_hung) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperPluginHung",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   UMA_HISTOGRAM_COUNTS_1M("Pepper.PluginHung", 1);
 
   observers_.NotifyObservers(&WebContentsObserver::PluginHungStatusChanged,
@@ -5996,16 +5952,14 @@
 void WebContentsImpl::OnPepperStartsPlayback(RenderFrameHostImpl* source,
                                              int32_t pp_instance) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperStartsPlayback",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   pepper_playback_observer_->PepperStartsPlayback(source, pp_instance);
 }
 
 void WebContentsImpl::OnPepperStopsPlayback(RenderFrameHostImpl* source,
                                             int32_t pp_instance) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperStopsPlayback",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   pepper_playback_observer_->PepperStopsPlayback(source, pp_instance);
 }
 
@@ -6013,8 +5967,7 @@
                                             const base::FilePath& plugin_path,
                                             base::ProcessId plugin_pid) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnPepperPluginCrashed",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   // TODO(nick): Eliminate the |plugin_pid| parameter, which can't be trusted,
   // and is only used by WebTestControlHost.
   observers_.NotifyObservers(&WebContentsObserver::PluginCrashed, plugin_path,
@@ -6027,8 +5980,7 @@
     RenderFrameHostImpl* source,
     std::vector<blink::mojom::FaviconURLPtr> candidates) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::UpdateFaviconURL",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source));
+                        "render_frame_host", source);
   // Ignore favicons for non-main frame.
   if (source->GetParent()) {
     NOTREACHED();
@@ -6058,7 +6010,7 @@
     RenderViewHostImpl* source) {
   OPTIONAL_TRACE_EVENT1("content",
                         "WebContentsImpl::DidFirstVisuallyNonEmptyPaint",
-                        "render_view_host", static_cast<void*>(source));
+                        "render_view_host", source);
   // TODO(nick): When this is ported to FrameHostMsg_, we should only listen if
   // |source| is the main frame.
   observers_.NotifyObservers(
@@ -6105,7 +6057,7 @@
 void WebContentsImpl::UpdateTitleForEntry(NavigationEntry* entry,
                                           const std::u16string& title) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::UpdateTitleForEntry",
-                        "title", base::trace_event::ValueToString(title));
+                        "title", title);
   std::u16string final_title;
   base::TrimWhitespace(title, base::TRIM_ALL, &final_title);
 
@@ -6201,8 +6153,7 @@
 void WebContentsImpl::NotifyViewSwapped(RenderViewHost* old_view,
                                         RenderViewHost* new_view) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::NotifyViewSwapped",
-                        "old_view", static_cast<void*>(old_view), "new_view",
-                        static_cast<void*>(new_view));
+                        "old_view", old_view, "new_view", new_view);
   DCHECK_NE(old_view, new_view);
   // After sending out a swap notification, we need to send a disconnect
   // notification so that clients that pick up a pointer to |this| can NULL the
@@ -6227,8 +6178,7 @@
                                          RenderFrameHostImpl* new_frame,
                                          bool is_main_frame) {
   TRACE_EVENT2("content", "WebContentsImpl::NotifyFrameSwapped", "old_frame",
-               base::trace_event::ToTracedValue(old_frame), "new_frame",
-               base::trace_event::ToTracedValue(new_frame));
+               old_frame, "new_frame", new_frame);
 #if defined(OS_ANDROID)
   // Copy importance from |old_frame| if |new_frame| is a main frame.
   if (old_frame && !new_frame->GetParent()) {
@@ -6277,8 +6227,7 @@
     mojo::ScopedInterfaceEndpointHandle handle) {
   OPTIONAL_TRACE_EVENT2(
       "content", "WebContentsImpl::OnAssociatedInterfaceRequest",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host),
-      "interface_name", interface_name);
+      "render_frame_host", render_frame_host, "interface_name", interface_name);
   auto it = receiver_sets_.find(interface_name);
   if (it != receiver_sets_.end())
     it->second->OnReceiverForFrame(render_frame_host, std::move(handle));
@@ -6289,8 +6238,7 @@
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle* interface_pipe) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnInterfaceRequest",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
+                        "render_frame_host", render_frame_host,
                         "interface_name", interface_name);
   for (auto& observer : observers_.observer_list()) {
     observer.OnInterfaceRequestFromFrame(render_frame_host, interface_name,
@@ -6304,12 +6252,16 @@
     const GURL& blocked_url,
     const GURL& initiator_url,
     blink::mojom::NavigationBlockedReason reason) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::OnDidBlockNavigation", "details",
-      base::trace_event::TracedValue::Build(
-          {{"blocked_url", base::trace_event::ValueToString(blocked_url)},
-           {"initiator_url", base::trace_event::ValueToString(initiator_url)},
-           {"reason", base::trace_event::ValueToString(reason)}}));
+  OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnDidBlockNavigation",
+                        "details", [&](perfetto::TracedValue context) {
+                          // TODO(crbug.com/1183371): Replace this with passing
+                          // more parameters to TRACE_EVENT directly when
+                          // available.
+                          auto dict = std::move(context).WriteDictionary();
+                          dict.Add("blocked_url", blocked_url);
+                          dict.Add("initiator_url", initiator_url);
+                          dict.Add("reason", reason);
+                        });
   if (delegate_)
     delegate_->OnDidBlockNavigation(this, blocked_url, initiator_url, reason);
 }
@@ -6321,7 +6273,7 @@
 void WebContentsImpl::RenderFrameCreated(
     RenderFrameHostImpl* render_frame_host) {
   TRACE_EVENT1("content", "WebContentsImpl::RenderFrameCreated",
-               "render_frame_host", static_cast<void*>(render_frame_host));
+               "render_frame_host", render_frame_host);
   // The WebContents tracks the process state for the main frame's renderer.
   // TODO(crbug.com/1164280): Under MPArch, with multiple frame trees in a
   // WebContents, this is intended to just track the main frame of the root
@@ -6359,8 +6311,7 @@
 void WebContentsImpl::RenderFrameDeleted(
     RenderFrameHostImpl* render_frame_host) {
   TRACE_EVENT1("content", "WebContentsImpl::RenderFrameDeleted",
-               "render_frame_host",
-               base::trace_event::ToTracedValue(render_frame_host));
+               "render_frame_host", render_frame_host);
   if (IsBeingDestroyed() && !render_frame_host->GetParent() &&
       first_navigation_completed_ &&
       !render_frame_host->IsInBackForwardCache()) {
@@ -6394,8 +6345,7 @@
         context_menu_client,
     const ContextMenuParams& params) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::ShowContextMenu",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   // If a renderer fires off a second command to show a context menu before the
   // first context menu is closed, just ignore it. https://crbug.com/707534
   if (showing_context_menu_)
@@ -6448,8 +6398,7 @@
     JavaScriptDialogType dialog_type,
     JavaScriptDialogCallback response_callback) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RunJavaScriptDialog",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   // Ensure that if showing a dialog is the first thing that a page does, that
   // the contents of the previous page aren't shown behind it. This is required
   // because showing a dialog freezes the renderer, so no frames will be coming
@@ -6531,9 +6480,8 @@
     bool is_reload,
     JavaScriptDialogCallback response_callback) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RunBeforeUnloadConfirm",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
-                        "is_reload", is_reload);
+                        "render_frame_host", render_frame_host, "is_reload",
+                        is_reload);
   // Ensure that if showing a dialog is the first thing that a page does, that
   // the contents of the previous page aren't shown behind it. This is required
   // because showing a dialog freezes the renderer, so no frames will be coming
@@ -6599,8 +6547,7 @@
     scoped_refptr<FileChooserImpl::FileSelectListenerImpl> listener,
     const blink::mojom::FileChooserParams& params) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RunFileChooser",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   // Any explicit focusing of another window while this WebContents is in
   // fullscreen can be used to confuse the user, so drop fullscreen.
   base::ScopedClosureRunner fullscreen_block = ForSecurityDropFullscreen();
@@ -6805,7 +6752,7 @@
 
 void WebContentsImpl::RenderViewReady(RenderViewHost* rvh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderViewReady",
-                        "render_view_host", static_cast<void*>(rvh));
+                        "render_view_host", rvh);
   if (rvh != GetRenderViewHost()) {
     // Don't notify the world, since this came from a renderer in the
     // background.
@@ -6827,7 +6774,7 @@
                                            base::TerminationStatus status,
                                            int error_code) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::RenderViewTerminated",
-                        "render_view_host", static_cast<void*>(rvh), "status",
+                        "render_view_host", rvh, "status",
                         static_cast<int>(status));
 
   // It is possible to get here while the WebContentsImpl is being destroyed,
@@ -6882,7 +6829,7 @@
 
 void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderViewDeleted",
-                        "render_view_host", static_cast<void*>(rvh));
+                        "render_view_host", rvh);
   observers_.NotifyObservers(&WebContentsObserver::RenderViewDeleted, rvh);
 }
 
@@ -6895,7 +6842,7 @@
 
 void WebContentsImpl::Close(RenderViewHost* rvh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::Close", "render_view_host",
-                        static_cast<void*>(rvh));
+                        rvh);
 #if defined(OS_MAC)
   // The UI may be in an event-tracking loop, such as between the
   // mouse-down and mouse-up in text selection or a button click.
@@ -6964,7 +6911,7 @@
 void WebContentsImpl::DidStartLoading(FrameTreeNode* frame_tree_node,
                                       bool to_different_document) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DidStartLoading",
-                        "frame_tree_node", static_cast<void*>(frame_tree_node));
+                        "frame_tree_node", frame_tree_node);
   LoadingStateChanged(frame_tree_node->IsMainFrame() && to_different_document,
                       nullptr);
 
@@ -7044,7 +6991,7 @@
     NavigationHandle* navigation_handle) {
   OPTIONAL_TRACE_EVENT1("content",
                         "WebContentsImpl::CreateThrottlesForNavigation",
-                        "navigation", static_cast<void*>(navigation_handle));
+                        "navigation", navigation_handle);
   auto throttles = GetContentClient()->browser()->CreateThrottlesForNavigation(
       navigation_handle);
 
@@ -7075,9 +7022,8 @@
   OPTIONAL_TRACE_EVENT2(
       "content",
       "WebContentsImpl::RegisterExistingOriginToPreventOptInIsolation",
-      "origin", base::trace_event::ValueToString(origin),
-      "navigation_request_to_exclude",
-      static_cast<void*>(navigation_request_to_exclude));
+      "origin", origin, "navigation_request_to_exclude",
+      navigation_request_to_exclude);
   // Note: This function can be made static if we ever need call it without
   // a WebContentsImpl instance, in which case we can use a wrapper to
   // implement the override from NavigatorDelegate.
@@ -7099,18 +7045,17 @@
 
 void WebContentsImpl::DidChangeName(RenderFrameHostImpl* render_frame_host,
                                     const std::string& name) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::DidChangeName", "render_frame_host",
-      base::trace_event::ToTracedValue(render_frame_host), "name", name);
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::DidChangeName",
+                        "render_frame_host", render_frame_host, "name", name);
   observers_.NotifyObservers(&WebContentsObserver::FrameNameChanged,
                              render_frame_host, name);
 }
 
 void WebContentsImpl::DidReceiveFirstUserActivation(
     RenderFrameHostImpl* render_frame_host) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::DidReceiveFirstUserActivation",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::DidReceiveFirstUserActivation",
+                        "render_frame_host", render_frame_host);
   observers_.NotifyObservers(
       &WebContentsObserver::FrameReceivedFirstUserActivation,
       render_frame_host);
@@ -7120,8 +7065,7 @@
     RenderFrameHostImpl* render_frame_host,
     bool is_display_none) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::DidChangeDisplayState",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
+                        "render_frame_host", render_frame_host,
                         "is_display_none", is_display_none);
   observers_.NotifyObservers(&WebContentsObserver::FrameDisplayStateChanged,
                              render_frame_host, is_display_none);
@@ -7130,8 +7074,7 @@
 void WebContentsImpl::FrameSizeChanged(RenderFrameHostImpl* render_frame_host,
                                        const gfx::Size& frame_size) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::FrameSizeChanged",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   observers_.NotifyObservers(&WebContentsObserver::FrameSizeChanged,
                              render_frame_host, frame_size);
 }
@@ -7139,8 +7082,7 @@
 void WebContentsImpl::DocumentOnLoadCompleted(
     RenderFrameHostImpl* render_frame_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DocumentOnLoadCompleted",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   ShowInsecureLocalhostWarningIfNeeded();
 
   GetRenderViewHost()->DocumentOnLoadCompletedInMainFrame();
@@ -7160,9 +7102,7 @@
                                   const std::u16string& title,
                                   base::i18n::TextDirection title_direction) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::UpdateTitle",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
-                        "title", base::trace_event::ValueToString(title));
+                        "render_frame_host", render_frame_host, "title", title);
   // Try to find the navigation entry, which might not be the current one.
   // For example, it might be from a recently swapped out RFH.
   NavigationEntryImpl* entry =
@@ -7186,9 +7126,7 @@
 void WebContentsImpl::UpdateTargetURL(RenderFrameHostImpl* render_frame_host,
                                       const GURL& url) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::UpdateTargetURL",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host),
-                        "url", base::trace_event::ValueToString(url));
+                        "render_frame_host", render_frame_host, "url", url);
   // In case of racey updates from multiple RenderViewHosts, the last URL should
   // be shown - see also some discussion in https://crbug.com/807776.
   if (!url.is_valid() && render_frame_host != frame_that_set_last_target_url_)
@@ -7203,10 +7141,9 @@
 bool WebContentsImpl::ShouldRouteMessageEvent(
     RenderFrameHostImpl* target_rfh,
     SiteInstance* source_site_instance) const {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::ShouldRouteMessageEvent",
-      "render_frame_host", base::trace_event::ToTracedValue(target_rfh),
-      "source_site_instance", static_cast<void*>(source_site_instance));
+  OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::ShouldRouteMessageEvent",
+                        "render_frame_host", target_rfh, "source_site_instance",
+                        source_site_instance);
   // Allow the message if this WebContents is dedicated to a browser plugin
   // guest.
   // Note: This check means that an embedder could theoretically receive a
@@ -7219,8 +7156,7 @@
 void WebContentsImpl::EnsureOpenerProxiesExist(
     RenderFrameHostImpl* source_rfh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::EnsureOpenerProxiesExist",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source_rfh));
+                        "render_frame_host", source_rfh);
   WebContentsImpl* source_web_contents = static_cast<WebContentsImpl*>(
       WebContents::FromRenderFrameHost(source_rfh));
 
@@ -7273,8 +7209,8 @@
 void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node,
                                       SiteInstance* source) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::SetFocusedFrame",
-                        "frame_tree_node", static_cast<void*>(node),
-                        "source_site_instance", static_cast<void*>(source));
+                        "frame_tree_node", node, "source_site_instance",
+                        source);
   frame_tree_.SetFocusedFrame(node, source);
 
   if (auto* inner_contents = node_.GetInnerWebContentsInFrame(node)) {
@@ -7341,8 +7277,7 @@
 
 void WebContentsImpl::OnAdvanceFocus(RenderFrameHostImpl* source_rfh) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnAdvanceFocus",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(source_rfh));
+                        "render_frame_host", source_rfh);
   // When a RenderFrame needs to advance focus to a RenderFrameProxy (by hitting
   // TAB), the RenderFrameProxy sends an IPC to RenderFrameProxyHost. When this
   // RenderFrameProxyHost represents an inner WebContents, the outer WebContents
@@ -7358,9 +7293,9 @@
     RenderFrameHostImpl* frame,
     const gfx::Rect& bounds_in_root_view,
     blink::mojom::FocusType focus_type) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::OnFocusedElementChangedInFrame",
-      "render_frame_host", base::trace_event::ToTracedValue(frame));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::OnFocusedElementChangedInFrame",
+                        "render_frame_host", frame);
   RenderWidgetHostViewBase* root_view =
       static_cast<RenderWidgetHostViewBase*>(GetRenderWidgetHostView());
   if (!root_view || !frame->GetView())
@@ -7398,7 +7333,7 @@
     const std::u16string& source_id,
     const base::Optional<std::u16string>& untrusted_stack_trace) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DidAddMessageToConsole",
-                        "message", base::trace_event::ValueToString(message));
+                        "message", message);
 
   observers_.NotifyObservers(&WebContentsObserver::OnDidAddMessageToConsole,
                              source_frame, log_level, message, line_no,
@@ -7414,8 +7349,7 @@
     RenderWidgetHostImpl* render_widget_host,
     const blink::WebInputEvent& event) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::DidReceiveInputEvent",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
 
   if (!IsUserInteractionInputType(event.GetType()))
     return;
@@ -7445,8 +7379,7 @@
 void WebContentsImpl::FocusOwningWebContents(
     RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::FocusOwningWebContents",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   RenderWidgetHostImpl* main_frame_widget_host =
       GetMainFrame()->GetRenderWidgetHost();
   RenderWidgetHostImpl* focused_widget =
@@ -7469,8 +7402,7 @@
     RenderWidgetHostImpl* render_widget_host,
     base::RepeatingClosure hang_monitor_restarter) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RendererUnresponsive",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   if (ShouldIgnoreUnresponsiveRenderer())
     return;
 
@@ -7494,8 +7426,7 @@
 void WebContentsImpl::RendererResponsive(
     RenderWidgetHostImpl* render_widget_host) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderResponsive",
-                        "render_widget_host",
-                        static_cast<void*>(render_widget_host));
+                        "render_widget_host", render_widget_host);
   observers_.NotifyObservers(&WebContentsObserver::OnRendererResponsive,
                              render_widget_host->GetProcess());
 
@@ -7506,8 +7437,7 @@
 void WebContentsImpl::SubframeCrashed(
     blink::mojom::FrameVisibility visibility) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::SubframeCrashed",
-                        "visibility",
-                        base::trace_event::ValueToString(visibility));
+                        "visibility", visibility);
   // If a subframe crashed on a hidden tab, mark the tab for reload to avoid
   // showing a sad frame to the user if they ever switch back to that tab. Do
   // this for subframes that are either visible in viewport or visible but
@@ -7562,10 +7492,9 @@
     RenderFrameHostImpl* old_frame,
     RenderFrameHostImpl* new_frame,
     bool is_main_frame) {
-  TRACE_EVENT2(
-      "content", "WebContentsImpl::NotifySwappedFromRenderManager",
-      "old_render_frame_host", base::trace_event::ToTracedValue(old_frame),
-      "new_render_frame_host", base::trace_event::ToTracedValue(new_frame));
+  TRACE_EVENT2("content", "WebContentsImpl::NotifySwappedFromRenderManager",
+               "old_render_frame_host", old_frame, "new_render_frame_host",
+               new_frame);
 
   FrameTree* frame_tree = new_frame->frame_tree();
 
@@ -7631,7 +7560,7 @@
     RenderViewHost* render_view_host) {
   OPTIONAL_TRACE_EVENT1(
       "content", "WebContentsImpl::CreateRenderWidgetHostViewForRenderManager",
-      "render_view_host", static_cast<void*>(render_view_host));
+      "render_view_host", render_view_host);
   RenderWidgetHostViewBase* rwh_view =
       view_->CreateViewForWidget(render_view_host->GetWidget());
   view_->SetOverscrollControllerEnabled(CanOverscrollContent());
@@ -7649,7 +7578,7 @@
     RenderFrameProxyHost* proxy_host) {
   TRACE_EVENT1("browser,navigation",
                "WebContentsImpl::CreateRenderViewForRenderManager",
-               "render_view_host", static_cast<void*>(render_view_host));
+               "render_view_host", render_view_host);
   auto* rvh_impl = static_cast<RenderViewHostImpl*>(render_view_host);
   // Observers should not destroy the WebContents here or we will crash as the
   // stack unwinds. See crbug.com/1181043.
@@ -7756,8 +7685,7 @@
     const std::vector<SkBitmap>& images,
     const std::vector<gfx::Size>& original_image_sizes) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnDidDownloadImage",
-                        "image_url",
-                        base::trace_event::ValueToString(image_url));
+                        "image_url", image_url);
   std::move(callback).Run(id, http_status_code, image_url, images,
                           original_image_sizes);
 }
@@ -7773,8 +7701,7 @@
   RenderFrameHostImpl* rfh = RenderFrameHostImpl::FromID(render_process_id,
                                                          render_frame_id);
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnDialogClosed",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(rfh));
+                        "render_frame_host", rfh);
   last_dialog_suppressed_ = dialog_was_suppressed;
   fullscreen_block.RunAndReset();
 
@@ -7902,10 +7829,8 @@
 }
 
 void WebContentsImpl::OnFrameTreeNodeDestroyed(FrameTreeNode* node) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::OnFrameTreeNodeDestroyed",
-      "render_frame_host",
-      base::trace_event::ToTracedValue(node->current_frame_host()));
+  OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnFrameTreeNodeDestroyed",
+                        "render_frame_host", node->current_frame_host());
   observers_.NotifyObservers(&WebContentsObserver::FrameDeleted,
                              node->current_frame_host());
 }
@@ -7923,8 +7848,7 @@
     RenderFrameHostImpl* frame_host,
     const GURL& url) {
   TRACE_EVENT2("content", "WebContentsImpl::CreateWebUI", "frame_host",
-               base::trace_event::ToTracedValue(frame_host), "url",
-               base::trace_event::ValueToString(url));
+               frame_host, "url", url);
   std::unique_ptr<WebUIImpl> web_ui =
       std::make_unique<WebUIImpl>(this, frame_host);
   std::unique_ptr<WebUIController> controller(
@@ -8333,9 +8257,9 @@
 
 void WebContentsImpl::AudioContextPlaybackStarted(RenderFrameHostImpl* host,
                                                   int context_id) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::AudioContextPlaybackStarted",
-      "render_frame_host", base::trace_event::ToTracedValue(host));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::AudioContextPlaybackStarted",
+                        "render_frame_host", host);
   WebContentsObserver::AudioContextId audio_context_id(host, context_id);
   observers_.NotifyObservers(&WebContentsObserver::AudioContextPlaybackStarted,
                              audio_context_id);
@@ -8343,9 +8267,9 @@
 
 void WebContentsImpl::AudioContextPlaybackStopped(RenderFrameHostImpl* host,
                                                   int context_id) {
-  OPTIONAL_TRACE_EVENT1(
-      "content", "WebContentsImpl::AudioContextPlaybackStopped",
-      "render_frame_host", base::trace_event::ToTracedValue(host));
+  OPTIONAL_TRACE_EVENT1("content",
+                        "WebContentsImpl::AudioContextPlaybackStopped",
+                        "render_frame_host", host);
   WebContentsObserver::AudioContextId audio_context_id(host, context_id);
   observers_.NotifyObservers(&WebContentsObserver::AudioContextPlaybackStopped,
                              audio_context_id);
@@ -8354,9 +8278,7 @@
 void WebContentsImpl::OnFrameAudioStateChanged(RenderFrameHostImpl* host,
                                                bool is_audible) {
   OPTIONAL_TRACE_EVENT2("content", "WebContentsImpl::OnFrameAudioStateChanged",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(host), "is_audible",
-                        is_audible);
+                        "render_frame_host", host, "is_audible", is_audible);
   observers_.NotifyObservers(&WebContentsObserver::OnFrameAudioStateChanged,
                              host, is_audible);
 }
@@ -8438,8 +8360,7 @@
     bool right_aligned,
     bool allow_multiple_selection) {
   OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::ShowPopupMenu",
-                        "render_frame_host",
-                        base::trace_event::ToTracedValue(render_frame_host));
+                        "render_frame_host", render_frame_host);
   if (show_poup_menu_callback_) {
     std::move(show_poup_menu_callback_).Run(bounds);
     return true;
@@ -8657,13 +8578,17 @@
     RenderFrameHostImpl* render_frame_host,
     LifecycleState old_state,
     LifecycleState new_state) {
-  OPTIONAL_TRACE_EVENT2(
-      "content", "WebContentsImpl::RenderFrameHostStateChanged",
-      "render_frame_host", base::trace_event::ToTracedValue(render_frame_host),
-      "states",
-      base::trace_event::TracedValue::Build(
-          {{"old", base::trace_event::ValueToString(old_state)},
-           {"new", base::trace_event::ValueToString(new_state)}}));
+  OPTIONAL_TRACE_EVENT2("content",
+                        "WebContentsImpl::RenderFrameHostStateChanged",
+                        "render_frame_host", render_frame_host, "states",
+                        [&](perfetto::TracedValue context) {
+                          // TODO(crbug.com/1183371): Replace this with passing
+                          // more parameters to TRACE_EVENT directly when
+                          // available.
+                          auto dict = std::move(context).WriteDictionary();
+                          dict.Add("old", old_state);
+                          dict.Add("new", new_state);
+                        });
   const bool was_in_back_forward_cache =
       old_state == LifecycleState::kInBackForwardCache;
   const bool is_in_back_forward_cache =
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 660dac1..df7f486 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -170,6 +170,7 @@
     "frame_accept_header.h",
     "frame_service_base.h",
     "generated_code_cache_settings.h",
+    "global_request_id.cc",
     "global_request_id.h",
     "global_routing_id.h",
     "gpu_client.h",
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index be407422..0f94985b 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -25,6 +25,7 @@
 #include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom-forward.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 
 #if !defined(OS_ANDROID)
 #include "content/public/browser/zoom_level_delegate.h"
@@ -367,6 +368,9 @@
   // nullptr if there isn't one.
   virtual variations::VariationsClient* GetVariationsClient();
 
+  // Write a representation of this object into a trace.
+  void WriteIntoTracedValue(perfetto::TracedValue context);
+
  private:
   const std::string unique_id_;
   bool was_notify_will_be_destroyed_called_ = false;
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index fb89f8a..93d3600 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -35,6 +35,7 @@
 #include "content/public/browser/overlay_window.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/quota_permission_context.h"
+#include "content/public/browser/sms_fetcher.h"
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "content/public/browser/vpn_service_proxy.h"
 #include "content/public/browser/web_contents.h"
@@ -1097,7 +1098,9 @@
     content::BrowserContext* browser_context,
     const url::Origin& origin,
     base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
-                            base::Optional<std::string>)> callback) {}
+                            base::Optional<std::string>,
+                            base::Optional<content::SmsFetchFailureType>)>
+        callback) {}
 
 bool ContentBrowserClient::IsClipboardPasteAllowed(
     content::RenderFrameHost* render_frame_host) {
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index fedf85b..78b8ea7 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -187,6 +187,7 @@
 
 namespace content {
 enum class PermissionType;
+enum class SmsFetchFailureType;
 class AuthenticatorRequestClientDelegate;
 class BluetoothDelegate;
 class BrowserChildProcessHost;
@@ -1890,13 +1891,15 @@
 
   // Requests an SMS from |origin| from a remote device with telephony
   // capabilities, for example the user's mobile phone. Callbacks |callback|
-  // with the origins and one-time-code from the SMS upon success or an empty
-  // response on error.
+  // with the origins and one-time-code from the SMS upon success or a failure
+  // type on error.
   virtual void FetchRemoteSms(
       content::BrowserContext* browser_context,
       const url::Origin& origin,
       base::OnceCallback<void(base::Optional<std::vector<url::Origin>>,
-                              base::Optional<std::string>)> callback);
+                              base::Optional<std::string>,
+                              base::Optional<content::SmsFetchFailureType>)>
+          callback);
 
   // Check whether paste is allowed. To paste, an implementation may require a
   // `render_frame_host` to have user activation or various permissions.
diff --git a/content/public/browser/global_request_id.cc b/content/public/browser/global_request_id.cc
new file mode 100644
index 0000000..2a1be82
--- /dev/null
+++ b/content/public/browser/global_request_id.cc
@@ -0,0 +1,18 @@
+// 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 "content/public/browser/global_request_id.h"
+
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
+
+namespace content {
+
+void GlobalRequestID::WriteIntoTracedValue(
+    perfetto::TracedValue context) const {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("child_id", child_id);
+  dict.Add("request_id", request_id);
+}
+
+}  // namespace content
diff --git a/content/public/browser/global_request_id.h b/content/public/browser/global_request_id.h
index d03dc97..656266d 100644
--- a/content/public/browser/global_request_id.h
+++ b/content/public/browser/global_request_id.h
@@ -8,6 +8,8 @@
 #include <atomic>
 #include <tuple>
 
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
+
 namespace content {
 
 // Uniquely identifies a net::URLRequest.
@@ -44,6 +46,8 @@
     return child_id != other.child_id ||
         request_id != other.request_id;
   }
+
+  void WriteIntoTracedValue(perfetto::TracedValue context) const;
 };
 
 }  // namespace content
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index 8f5b2f3fb..468fabaf 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -27,6 +27,7 @@
 #include "third_party/blink/public/common/tokens/tokens.h"
 #include "third_party/blink/public/mojom/loader/referrer.mojom.h"
 #include "third_party/blink/public/mojom/loader/transferrable_url_loader.mojom.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "ui/base/page_transition_types.h"
 
 class GURL;
@@ -441,6 +442,9 @@
   // navigation or an error page.
   virtual bool IsWaitingToCommit() = 0;
 
+  // Write a representation of this object into a trace.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
+
   // Testing methods ----------------------------------------------------------
   //
   // The following methods should be used exclusively for writing unit tests.
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index fda7baa..e8a6300 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -744,11 +744,8 @@
   // created on the document.
   virtual bool DocumentUsedWebOTP() = 0;
 
-  // Write a description of this RenderFrameHost into provided |traced_value|.
-  // The caller is responsible for ensuring that key-value pairs can be written
-  // into |traced_value| — either by creating a new TracedValue or calling
-  // BeginDictionary() before calling this method.
-  virtual void AsValueInto(base::trace_event::TracedValue* traced_value) = 0;
+  // Write a description of this RenderFrameHost into the provided |context|.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
 
   // Start/stop event log output from WebRTC on this RFH for the peer connection
   // identified locally within the RFH using the ID `lid`.
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index d3aa6b1..0dc18bb 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -46,6 +46,7 @@
 #include "third_party/blink/public/mojom/permissions/permission.mojom-forward.h"
 #include "third_party/blink/public/mojom/quota/quota_manager_host.mojom-forward.h"
 #include "third_party/blink/public/mojom/websockets/websocket_connector.mojom-forward.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "ui/gfx/native_widget_types.h"
 
 #if defined(OS_ANDROID)
@@ -543,6 +544,9 @@
   // the BrowserContext they are associated with.
   virtual std::string GetInfoForBrowserContextDestructionCrashReporting() = 0;
 
+  // Write a representation of this object into a trace.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
+
 #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX)
   // Ask the renderer process to dump its profiling data to disk. Invokes
   // |callback| once this has completed.
diff --git a/content/public/browser/render_view_host.h b/content/public/browser/render_view_host.h
index 0edd8ddc..59b281ca 100644
--- a/content/public/browser/render_view_host.h
+++ b/content/public/browser/render_view_host.h
@@ -88,6 +88,9 @@
   // Returns true if the RenderView is active and has not crashed.
   virtual bool IsRenderViewLive() = 0;
 
+  // Write a representation of this object into a trace.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
+
  private:
   // This interface should only be implemented inside content.
   friend class RenderViewHostImpl;
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h
index 8eec86b..0352cf4 100644
--- a/content/public/browser/render_widget_host.h
+++ b/content/public/browser/render_widget_host.h
@@ -23,6 +23,7 @@
 #include "third_party/blink/public/common/input/web_input_event.h"
 #include "third_party/blink/public/common/page/drag_operation.h"
 #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
 #include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/surface/transport_dib.h"
@@ -289,6 +290,9 @@
   // Get the allowed touch action corresponding to this RenderWidgetHost.
   virtual base::Optional<cc::TouchAction> GetAllowedTouchAction() = 0;
 
+  // Write a representation of this object into a trace.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
+
   // Drag-and-drop drop target messages that get sent to Blink.
   virtual void DragTargetDragEnter(const DropData& drop_data,
                                    const gfx::PointF& client_pt,
diff --git a/content/public/browser/site_instance.h b/content/public/browser/site_instance.h
index 25502c2f..9b90d52 100644
--- a/content/public/browser/site_instance.h
+++ b/content/public/browser/site_instance.h
@@ -176,6 +176,9 @@
   // affects performance.
   virtual SiteInstanceProcessAssignment GetLastProcessAssignmentOutcome() = 0;
 
+  // Write a representation of this object into a trace.
+  virtual void WriteIntoTracedValue(perfetto::TracedValue context) = 0;
+
   // Factory method to create a new SiteInstance.  This will create a new
   // BrowsingInstance, so it should only be used when creating a new tab from
   // scratch (or similar circumstances).
diff --git a/content/public/browser/sms_fetcher.h b/content/public/browser/sms_fetcher.h
index 7d88e3d..ce19cb7 100644
--- a/content/public/browser/sms_fetcher.h
+++ b/content/public/browser/sms_fetcher.h
@@ -19,6 +19,21 @@
 class BrowserContext;
 class RenderFrameHost;
 
+enum class SmsFetchFailureType {
+  kNoFailure = 0,
+  kSmsNotParsed_OTPFormatRegexNotMatch = 1,
+  kSmsNotParsed_HostAndPortNotParsed = 2,
+  kSmsNotParsed_kGURLNotValid = 3,
+
+  kPromptTimeout = 4,
+  kPromptCancelled = 5,
+
+  // The underlying API is not available
+  kBackendNotAvailable = 6,
+  kMaxValue = kBackendNotAvailable,
+};
+
+// TODO(yigu): Do not use anonymous namespace in header.
 namespace {
 using OriginList = std::vector<url::Origin>;
 }  // namespace
@@ -28,19 +43,6 @@
 // There is one SmsFetcher per profile.
 class SmsFetcher {
  public:
-  enum class FailureType {
-    kSmsNotParsed_OTPFormatRegexNotMatch = 0,
-    kSmsNotParsed_HostAndPortNotParsed = 1,
-    kSmsNotParsed_kGURLNotValid = 2,
-
-    kPromptTimeout = 3,
-    kPromptCancelled = 4,
-
-    // The underlying API is not available
-    kBackendNotAvailable = 5,
-    kMaxValue = kBackendNotAvailable,
-  };
-
   // Indicates whether the subscriber needs to obtain its own user consent or
   // not.
   enum class UserConsent {
@@ -68,7 +70,7 @@
     virtual void OnReceive(const OriginList& origin_list,
                            const std::string& one_time_code,
                            UserConsent) = 0;
-    virtual void OnFailure(FailureType failure_type) = 0;
+    virtual void OnFailure(SmsFetchFailureType failure_type) = 0;
   };
 
   // Subscribes to incoming SMSes from SmsProvider for subscribers that do not
diff --git a/content/public/test/mock_navigation_handle.h b/content/public/test/mock_navigation_handle.h
index cc60c1e..763f655 100644
--- a/content/public/test/mock_navigation_handle.h
+++ b/content/public/test/mock_navigation_handle.h
@@ -21,6 +21,7 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/mojom/loader/referrer.mojom.h"
+#include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -160,6 +161,9 @@
   MOCK_METHOD(void, SetSilentlyIgnoreErrors, ());
   MOCK_METHOD(network::mojom::WebSandboxFlags, SandboxFlagsToCommit, ());
   MOCK_METHOD(bool, IsWaitingToCommit, ());
+  void WriteIntoTracedValue(perfetto::TracedValue context) override {
+    auto dict = std::move(context).WriteDictionary();
+  }
 
   void set_url(const GURL& url) { url_ = url; }
   void set_previous_main_frame_url(const GURL& previous_main_frame_url) {
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index c1cde93..844b85a 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -465,6 +465,12 @@
   return std::string();
 }
 
+void MockRenderProcessHost::WriteIntoTracedValue(
+    perfetto::TracedValue context) {
+  auto dict = std::move(context).WriteDictionary();
+  dict.Add("id", GetID());
+}
+
 void MockRenderProcessHost::FilterURL(bool empty_allowed, GURL* url) {
   RenderProcessHostImpl::FilterURL(this, empty_allowed, url);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index c4be1f7d..826c2234 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -221,6 +221,7 @@
 
   void CleanupNetworkServicePluginExceptionsUponDestruction() override;
   std::string GetInfoForBrowserContextDestructionCrashReporting() override;
+  void WriteIntoTracedValue(perfetto::TracedValue context) override;
 
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
diff --git a/content/public/test/test_navigation_observer.cc b/content/public/test/test_navigation_observer.cc
index c61f0dfd3..94c6a731 100644
--- a/content/public/test/test_navigation_observer.cc
+++ b/content/public/test/test_navigation_observer.cc
@@ -112,12 +112,23 @@
 }
 
 void TestNavigationObserver::Wait() {
+  TRACE_EVENT1("test", "TestNavigationObserver::Wait", "params",
+               [&](perfetto::TracedValue ctx) {
+                 // TODO(crbug.com/1183371): Replace this with passing more
+                 // parameters to TRACE_EVENT directly when available.
+                 auto dict = std::move(ctx).WriteDictionary();
+                 dict.Add("wait_event", wait_event_);
+                 dict.Add("ignore_uncommitted_navigations",
+                          ignore_uncommitted_navigations_);
+                 dict.Add("target_url", target_url_);
+                 dict.Add("target_error", target_error_);
+               });
   message_loop_runner_->Run();
 }
 
 void TestNavigationObserver::WaitForNavigationFinished() {
   wait_event_ = WaitEvent::kNavigationFinished;
-  message_loop_runner_->Run();
+  Wait();
 }
 
 void TestNavigationObserver::StartWatchingNewWebContents() {
diff --git a/content/test/data/prerender/restriction_indexeddb.html b/content/test/data/prerender/restriction_indexeddb.html
deleted file mode 100644
index 94679b5..0000000
--- a/content/test/data/prerender/restriction_indexeddb.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head></head>
-<body>
-<script src="test_utils.js"></script>
-<script>
-
-const STORAGE_NAME = 'prerender_test';
-
-async function openDatabase() {
-  return new Promise(resolve => {
-    const request = window.indexedDB.open(STORAGE_NAME);
-    request.onupgradeneeded = e => {
-      const db = e.target.result;
-      const objectStore =
-        db.createObjectStore(STORAGE_NAME, {
-          autoIncrement: true
-        });
-      objectStore.createIndex('key', 'key', {
-        unique: true
-      });
-    };
-    request.onerror = e => {
-      resolve(null);
-    };
-    request.onsuccess = e => {
-      resolve(e.target.result);
-    };
-  });
-}
-
-async function addData(key, value) {
-  const db = await openDatabase();
-  if (!db) {
-    return Promise.reject('Failed to open database.');
-  }
-  return new Promise((resolve, reject) => {
-    const transaction = db.transaction(STORAGE_NAME, 'readwrite');
-    const request =
-      transaction.objectStore(STORAGE_NAME).add({
-        'key': key,
-        'value': value
-      });
-    // Use `transaction.oncomplete` rather than `request.onsuccess` to ensure
-    // that IndexedDB has flushed to disk.
-    transaction.oncomplete = e => {
-      resolve(true);
-    }
-    transaction.onerror = e => {
-      reject(e.target.error);
-    }
-  });
-}
-
-async function readData(key) {
-  const db = await openDatabase();
-  if (!db) {
-    return Promise.reject('Failed to open database.');
-  }
-  return new Promise((resolve, reject) => {
-    const transaction = db.transaction(STORAGE_NAME);
-    const request = transaction.objectStore(STORAGE_NAME).index('key').get(key);
-    request.onsuccess = e => {
-      if (e.target.result) {
-        resolve(e.target.result.value);
-      } else {
-        reject(new Error("Empty result."));
-      }
-    };
-    request.onerror = e => {
-      reject(e.target.error);
-    };
-  });
-}
-
-</script>
-</body>
-</html>
diff --git a/content/test/gpu/fuchsia_util.py b/content/test/gpu/fuchsia_util.py
index 32207df..a268e08 100644
--- a/content/test/gpu/fuchsia_util.py
+++ b/content/test/gpu/fuchsia_util.py
@@ -21,44 +21,45 @@
 
 def RunTestOnFuchsiaDevice(script_cmd):
   """Preps Fuchsia device with pave and package update, then runs script."""
+
   parser = argparse.ArgumentParser()
   AddCommonArgs(parser)
-  args, test_args = parser.parse_known_args()
-  ConfigureLogging(args)
+  runner_script_args, test_args = parser.parse_known_args()
+  ConfigureLogging(runner_script_args)
 
-  additional_target_args = {}
-
-  # If output_dir is not set, assume the script is being launched
+  # If out_dir is not set, assume the script is being launched
   # from the output directory.
-  if not args.out_dir:
-    args.out_dir = os.getcwd()
-    additional_target_args['out_dir'] = args.out_dir
+  if not runner_script_args.out_dir:
+    runner_script_args.out_dir = os.getcwd()
 
   # Create a temporary log file that Telemetry will look to use to build
   # an artifact when tests fail.
   temp_log_file = False
-  if not args.system_log_file:
-    args.system_log_file = os.path.join(tempfile.mkdtemp(), 'system-log')
+  if not runner_script_args.system_log_file:
+    runner_script_args.system_log_file = os.path.join(tempfile.mkdtemp(),
+                                                      'system-log')
     temp_log_file = True
-    additional_target_args['system_log_file'] = args.system_log_file
 
   package_names = ['web_engine_with_webui', 'web_engine_shell']
-  web_engine_dir = os.path.join(args.out_dir, 'gen', 'fuchsia', 'engine')
+  web_engine_dir = os.path.join(runner_script_args.out_dir, 'gen', 'fuchsia',
+                                'engine')
 
-  # Pass all other arguments to the integration tests.
+  # Pass all other arguments to the gpu integration tests.
   script_cmd.extend(test_args)
   try:
-    with GetDeploymentTargetForArgs(additional_target_args) as target:
+    with GetDeploymentTargetForArgs(runner_script_args) as target:
       target.Start()
       fuchsia_device_address, fuchsia_ssh_port = target._GetEndpoint()
-      script_cmd.extend(['--chromium-output-directory', args.out_dir])
+      script_cmd.extend(
+          ['--chromium-output-directory', runner_script_args.out_dir])
       script_cmd.extend(['--fuchsia-device-address', fuchsia_device_address])
       script_cmd.extend(['--fuchsia-ssh-config', target._GetSshConfigPath()])
       if fuchsia_ssh_port:
         script_cmd.extend(['--fuchsia-ssh-port', str(fuchsia_ssh_port)])
-      script_cmd.extend(['--fuchsia-system-log-file', args.system_log_file])
+      script_cmd.extend(
+          ['--fuchsia-system-log-file', runner_script_args.system_log_file])
       # Add to the script
-      if args.verbose:
+      if runner_script_args.verbose:
         script_cmd.append('-v')
 
       # Set up logging of WebEngine
@@ -68,7 +69,8 @@
       build_ids_paths = map(
           lambda package_name: os.path.join(web_engine_dir, package_name,
                                             'ids.txt'), package_names)
-      RunSymbolizer(listener.stdout, open(args.system_log_file, 'w'),
+      RunSymbolizer(listener.stdout,
+                    open(runner_script_args.system_log_file, 'w'),
                     build_ids_paths)
 
       # Keep the Amber repository live while the test runs.
@@ -82,4 +84,4 @@
         return subprocess.call(script_cmd)
   finally:
     if temp_log_file:
-      shutil.rmtree(os.path.dirname(args.system_log_file))
+      shutil.rmtree(os.path.dirname(runner_script_args.system_log_file))
diff --git a/docs/enterprise/active_directory_native_integration.md b/docs/enterprise/active_directory_native_integration.md
index 8c5fdc4..8f2cd4b5 100644
--- a/docs/enterprise/active_directory_native_integration.md
+++ b/docs/enterprise/active_directory_native_integration.md
@@ -78,7 +78,7 @@
 account is a shadow Gaia account with scope limited to the Play Store. To prove
 the user's identity, a SAML flow is employed with DM Server as service provider
 and AD (or really any other) as identity provider. The SAML flow is triggered by
-[ArcActiveDirectoryEnrollmentTokenFetcher](https://cs.chromium.org/chromium/src/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher.h).
+[ArcActiveDirectoryEnrollmentTokenFetcher](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ash/arc/auth/arc_active_directory_enrollment_token_fetcher.h).
 
 ### Instructions for Google Employees
 See [go/cros-ad-test-env](https://goto.google.com/cros-ad-test-env) for setting
diff --git a/docs/navigation_concepts.md b/docs/navigation_concepts.md
index faec12d..644f3e2 100644
--- a/docs/navigation_concepts.md
+++ b/docs/navigation_concepts.md
@@ -21,6 +21,8 @@
 * Navigating to a fragment within an existing document (e.g.
   `https://foo.com/1.html#fragment`).
 * A document calling the `history.pushState()` or `history.replaceState()` APIs.
+* A new document created via `document.open()`, which may change the URL to
+  match the document that initiated the call (possibly from another frame).
 * A session history navigation that stays in the same document, such as going
   back/forward to an existing entry for the same document.
 
diff --git a/docs/win_cross.md b/docs/win_cross.md
index b8a6ab5..bc6d9e0 100644
--- a/docs/win_cross.md
+++ b/docs/win_cross.md
@@ -37,8 +37,10 @@
 
 1. `gclient sync`, follow instructions on screen.
 
-If you're at Google, this will automatically download the Windows SDK for you.
-If this fails with an error:
+### If you're at Google
+
+`gclient sync` should automatically download the Windows SDK for you. If this
+fails with an error:
 
     Please follow the instructions at
     https://chromium.googlesource.com/chromium/src/+/HEAD/docs/win_cross.md
@@ -49,8 +51,13 @@
     # Follow instructions, enter 0 as project id.
     download_from_google_storage --config
 
-If you are not at Google, you can package your Windows SDK installation
-into a zip file by running the following on a Windows machine:
+`gclient sync` should now succeed. Skip ahead to the [GN setup](#gn-setup)
+section.
+
+### If you're not at Google
+
+You can package your Windows SDK installation into a zip file by running the
+following on a Windows machine:
 
     cd path/to/depot_tools/win_toolchain
     # customize the Windows SDK version numbers
diff --git a/extensions/browser/api/automation_internal/automation_internal_api.cc b/extensions/browser/api/automation_internal/automation_internal_api.cc
index d1583c52..55f3702 100644
--- a/extensions/browser/api/automation_internal/automation_internal_api.cc
+++ b/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -39,8 +39,8 @@
 #include "extensions/common/permissions/permissions_data.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_action_handler_base.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_enum_util.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
@@ -353,7 +353,8 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
   ui::AXTreeID ax_tree_id = ui::AXTreeID::FromString(params->tree_id);
-  ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
+  ui::AXActionHandlerRegistry* registry =
+      ui::AXActionHandlerRegistry::GetInstance();
   ui::AXActionHandlerBase* action_handler =
       registry->GetActionHandler(ax_tree_id);
   if (action_handler) {
@@ -590,7 +591,8 @@
   using api::automation_internal::PerformAction::Params;
   std::unique_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
-  ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
+  ui::AXActionHandlerRegistry* registry =
+      ui::AXActionHandlerRegistry::GetInstance();
   ui::AXActionHandlerBase* action_handler = registry->GetActionHandler(
       ui::AXTreeID::FromString(params->args.tree_id));
   if (action_handler) {
diff --git a/extensions/browser/api/management/management_api.cc b/extensions/browser/api/management/management_api.cc
index a65da475..3553c10 100644
--- a/extensions/browser/api/management/management_api.cc
+++ b/extensions/browser/api/management/management_api.cc
@@ -364,9 +364,9 @@
   }
 
   std::string error;
-  scoped_refptr<Extension> extension =
-      Extension::Create(base::FilePath(), Manifest::INVALID_LOCATION,
-                        *parsed_manifest, Extension::NO_FLAGS, &error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      base::FilePath(), mojom::ManifestLocation::kInvalidLocation,
+      *parsed_manifest, Extension::NO_FLAGS, &error);
   // TODO(lazyboy): Do we need to use |error|?
   if (!extension) {
     Respond(Error(keys::kExtensionCreateError));
diff --git a/extensions/browser/api/storage/settings_test_util.cc b/extensions/browser/api/storage/settings_test_util.cc
index 9ad3a38..18f5cc1 100644
--- a/extensions/browser/api/storage/settings_test_util.cc
+++ b/extensions/browser/api/storage/settings_test_util.cc
@@ -100,12 +100,8 @@
 
   std::string error;
   scoped_refptr<const Extension> extension(
-      Extension::Create(base::FilePath(),
-                        Manifest::INTERNAL,
-                        manifest,
-                        Extension::NO_FLAGS,
-                        id,
-                        &error));
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                        manifest, Extension::NO_FLAGS, id, &error));
   DCHECK(extension.get());
   DCHECK(error.empty());
 
diff --git a/extensions/browser/content_verifier_unittest.cc b/extensions/browser/content_verifier_unittest.cc
index 6d7edf2..5225d8c 100644
--- a/extensions/browser/content_verifier_unittest.cc
+++ b/extensions/browser/content_verifier_unittest.cc
@@ -233,8 +233,9 @@
     EXPECT_TRUE(base::PathService::Get(DIR_TEST_DATA, &path));
 
     std::string error;
-    scoped_refptr<Extension> extension(Extension::Create(
-        path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, &error));
+    scoped_refptr<Extension> extension(
+        Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
+                          Extension::NO_FLAGS, &error));
     EXPECT_TRUE(extension.get()) << error;
     return extension;
   }
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index c4af8d9..4bac6ba 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1606,6 +1606,7 @@
   FILEMANAGERPRIVATEINTERNAL_GETVOLUMEROOT = 1543,
   LANGUAGESETTINGSPRIVATE_GETALWAYSTRANSLATELANGUAGES = 1544,
   LANGUAGESETTINGSPRIVATE_SETLANGUAGEALWAYSTRANSLATESTATE = 1545,
+  ACCESSIBILITY_PRIVATE_SHOWCONFIRMATIONDIALOG = 1546,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/extension_icon_image_unittest.cc b/extensions/browser/extension_icon_image_unittest.cc
index 306dcc6..e132e1d 100644
--- a/extensions/browser/extension_icon_image_unittest.cc
+++ b/extensions/browser/extension_icon_image_unittest.cc
@@ -24,6 +24,8 @@
 #include "ui/gfx/image/image_skia_source.h"
 #include "ui/gfx/skia_util.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 namespace {
 
@@ -84,7 +86,7 @@
   }
 
   scoped_refptr<Extension> CreateExtension(const char* name,
-                                           Manifest::Location location) {
+                                           ManifestLocation location) {
     // Create and load an extension.
     base::FilePath test_file;
     if (!base::PathService::Get(DIR_TEST_DATA, &test_file)) {
@@ -137,7 +139,7 @@
   supported_factors.push_back(ui::SCALE_FACTOR_200P);
   ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -211,7 +213,7 @@
   supported_factors.push_back(ui::SCALE_FACTOR_200P);
   ui::test::ScopedSetSupportedScaleFactors scoped_supported(supported_factors);
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -249,7 +251,7 @@
 // one. The bigger resource should be loaded.
 TEST_F(ExtensionIconImageTest, FallbackToBigger) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -286,7 +288,7 @@
 // default icon, without notifying observer of image change.
 TEST_F(ExtensionIconImageTest, NoResources) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   ExtensionIconSet empty_icon_set;
@@ -326,7 +328,7 @@
 // return the default icon representation once image load is done.
 TEST_F(ExtensionIconImageTest, InvalidResource) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   const int kInvalidIconSize = 24;
@@ -363,7 +365,7 @@
 // icon when IconImage returns synchronously.
 TEST_F(ExtensionIconImageTest, LazyDefaultIcon) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -402,7 +404,7 @@
 // icon when IconImage returns asynchronously.
 TEST_F(ExtensionIconImageTest, LazyDefaultIcon_AsyncIconImage) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -444,7 +446,7 @@
 // representations should be returned.
 TEST_F(ExtensionIconImageTest, IconImageDestruction) {
   scoped_refptr<Extension> extension(CreateExtension(
-      "extension_icon_image", Manifest::INVALID_LOCATION));
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   gfx::ImageSkia default_icon = GetDefaultIcon();
@@ -493,8 +495,8 @@
 // cached for future use.
 TEST_F(ExtensionIconImageTest, ImageCachesNewRepresentations) {
   // Load up an extension and create an icon image.
-  scoped_refptr<Extension> extension(
-      CreateExtension("extension_icon_image", Manifest::INVALID_LOCATION));
+  scoped_refptr<Extension> extension(CreateExtension(
+      "extension_icon_image", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
   gfx::ImageSkia default_icon = GetDefaultIcon();
   std::unique_ptr<IconImage> icon_image(new IconImage(
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc
index f5d05d1..5b87b31d 100644
--- a/extensions/browser/image_loader_unittest.cc
+++ b/extensions/browser/image_loader_unittest.cc
@@ -32,6 +32,8 @@
 #include "ui/gfx/image/image_family.h"
 #include "ui/gfx/image/image_skia.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 class ImageLoaderTest : public ExtensionsTest {
@@ -65,7 +67,7 @@
   }
 
   scoped_refptr<Extension> CreateExtension(const char* dir_name,
-                                           Manifest::Location location) {
+                                           ManifestLocation location) {
     // Create and load an extension.
     base::FilePath extension_dir;
     if (!base::PathService::Get(DIR_TEST_DATA, &extension_dir)) {
@@ -103,7 +105,7 @@
 // Tests loading an image works correctly.
 TEST_F(ImageLoaderTest, LoadImage) {
   scoped_refptr<Extension> extension(
-      CreateExtension("image_loader", Manifest::INVALID_LOCATION));
+      CreateExtension("image_loader", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   ExtensionResource image_resource =
@@ -135,7 +137,7 @@
 // problems.
 TEST_F(ImageLoaderTest, DeleteExtensionWhileWaitingForCache) {
   scoped_refptr<Extension> extension(
-      CreateExtension("image_loader", Manifest::INVALID_LOCATION));
+      CreateExtension("image_loader", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   ExtensionResource image_resource =
@@ -176,7 +178,7 @@
 // Tests loading multiple dimensions of the same image.
 TEST_F(ImageLoaderTest, MultipleImages) {
   scoped_refptr<Extension> extension(
-      CreateExtension("image_loader", Manifest::INVALID_LOCATION));
+      CreateExtension("image_loader", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   std::vector<ImageLoader::ImageRepresentation> info_list;
@@ -219,7 +221,7 @@
 // Tests loading multiple dimensions of the same image into an image family.
 TEST_F(ImageLoaderTest, LoadImageFamily) {
   scoped_refptr<Extension> extension(
-      CreateExtension("image_loader", Manifest::INVALID_LOCATION));
+      CreateExtension("image_loader", ManifestLocation::kInvalidLocation));
   ASSERT_TRUE(extension.get() != nullptr);
 
   std::vector<ImageLoader::ImageRepresentation> info_list;
diff --git a/extensions/browser/requirements_checker_unittest.cc b/extensions/browser/requirements_checker_unittest.cc
index aabd457..3784c24 100644
--- a/extensions/browser/requirements_checker_unittest.cc
+++ b/extensions/browser/requirements_checker_unittest.cc
@@ -60,8 +60,8 @@
 
     std::string error;
     extension_ =
-        Extension::Create(base::FilePath(), Manifest::UNPACKED, *manifest_dict_,
-                          Extension::NO_FLAGS, &error);
+        Extension::Create(base::FilePath(), mojom::ManifestLocation::kUnpacked,
+                          *manifest_dict_, Extension::NO_FLAGS, &error);
     ASSERT_TRUE(extension_.get()) << error;
   }
 
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 883d111..0c28389e 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -188,7 +188,7 @@
     SandboxedUnpackerClient* client)
     : client_(client),
       extensions_dir_(extensions_dir),
-      location_(location),
+      location_(static_cast<mojom::ManifestLocation>(location)),
       creation_flags_(creation_flags),
       unpacker_io_task_runner_(unpacker_io_task_runner) {
   // Tracking for crbug.com/692069. The location must be valid. If it's invalid,
diff --git a/extensions/browser/sandboxed_unpacker.h b/extensions/browser/sandboxed_unpacker.h
index 7cb93812..feec851e 100644
--- a/extensions/browser/sandboxed_unpacker.h
+++ b/extensions/browser/sandboxed_unpacker.h
@@ -292,7 +292,7 @@
   std::string extension_id_;
 
   // Location to use for the unpacked extension.
-  Manifest::Location location_;
+  mojom::ManifestLocation location_;
 
   // Creation flags to use for the extension. These flags will be used
   // when calling Extension::Create() by the CRX installer.
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 44e1cc88..5ec0cd8 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -521,7 +521,8 @@
   },{
     "contexts": ["webui"],
     "matches": [
-      "chrome://password-change/*"
+      "chrome://password-change/*",
+      "chrome://file-manager/*"
     ]
   }],
   "runtime.sendNativeMessage": {
diff --git a/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc b/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
index 67653ed..de412a2 100644
--- a/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
+++ b/extensions/common/api/declarative_net_request/dnr_manifest_unittest.cc
@@ -287,8 +287,8 @@
 
   std::string error;
   scoped_refptr<Extension> extension = Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, *CreateManifest({ruleset}),
-      Extension::FROM_WEBSTORE, &error);
+      base::FilePath(), mojom::ManifestLocation::kInternal,
+      *CreateManifest({ruleset}), Extension::FROM_WEBSTORE, &error);
 
   EXPECT_TRUE(extension);
   EXPECT_TRUE(error.empty()) << error;
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 0a09f7e5..96ec1c0b 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -48,6 +48,8 @@
 #include "net/base/filename_util.h"
 #include "url/url_util.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 
 namespace keys = manifest_keys;
@@ -201,7 +203,7 @@
 
 // static
 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
-                                           Manifest::Location location,
+                                           ManifestLocation location,
                                            const base::DictionaryValue& value,
                                            int flags,
                                            std::string* utf8_error) {
@@ -216,7 +218,7 @@
 // TODO(sungguk): Continue removing std::string errors and replacing
 // with std::u16string. See http://crbug.com/71980.
 scoped_refptr<Extension> Extension::Create(const base::FilePath& path,
-                                           Manifest::Location location,
+                                           ManifestLocation location,
                                            const base::DictionaryValue& value,
                                            int flags,
                                            const std::string& explicit_id,
@@ -238,8 +240,9 @@
     manifest = Manifest::CreateManifestForLoginScreen(
         location, value.CreateDeepCopy(), std::move(extension_id));
   } else {
-    manifest = std::make_unique<Manifest>(location, value.CreateDeepCopy(),
-                                          std::move(extension_id));
+    manifest = std::make_unique<Manifest>(
+        static_cast<Manifest::Location>(location), value.CreateDeepCopy(),
+        std::move(extension_id));
   }
 
   std::vector<InstallWarning> install_warnings;
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index 505e7c9b..87ce7ffc 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -25,6 +25,7 @@
 #include "extensions/common/hashed_extension_id.h"
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 #include "extensions/common/url_pattern_set.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -156,7 +157,7 @@
   static const int kInitFromValueFlagBits;
 
   static scoped_refptr<Extension> Create(const base::FilePath& path,
-                                         Manifest::Location location,
+                                         mojom::ManifestLocation location,
                                          const base::DictionaryValue& value,
                                          int flags,
                                          std::string* error);
@@ -164,7 +165,7 @@
   // In a few special circumstances, we want to create an Extension and give it
   // an explicit id. Most consumers should just use the other Create() method.
   static scoped_refptr<Extension> Create(const base::FilePath& path,
-                                         Manifest::Location location,
+                                         mojom::ManifestLocation location,
                                          const base::DictionaryValue& value,
                                          int flags,
                                          const ExtensionId& explicit_id,
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index 1975fde..0bb6f91 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -155,7 +155,7 @@
 
   std::string error;
   scoped_refptr<const Extension> extension = Extension::Create(
-      path_, static_cast<Manifest::Location>(location_),
+      path_, location_,
       manifest_data_ ? *manifest_data_->GetValue() : *manifest_value_, flags_,
       id_, &error);
 
diff --git a/extensions/common/extension_messages.cc b/extensions/common/extension_messages.cc
index 76cde50..9e455509 100644
--- a/extensions/common/extension_messages.cc
+++ b/extensions/common/extension_messages.cc
@@ -101,8 +101,9 @@
   // We pass in the |id| to the create call because it will save work in the
   // normal case, and because in tests, extensions may not have paths or keys,
   // but it's important to retain the same id.
-  scoped_refptr<Extension> extension =
-      Extension::Create(path, location, manifest, creation_flags, id, error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      path, static_cast<extensions::mojom::ManifestLocation>(location),
+      manifest, creation_flags, id, error);
   if (extension.get()) {
     const extensions::PermissionsData* permissions_data =
         extension->permissions_data();
diff --git a/extensions/common/extension_set_unittest.cc b/extensions/common/extension_set_unittest.cc
index 199b32c..da6f4bd 100644
--- a/extensions/common/extension_set_unittest.cc
+++ b/extensions/common/extension_set_unittest.cc
@@ -45,7 +45,7 @@
 
   std::string error;
   scoped_refptr<Extension> extension(
-      Extension::Create(path, Manifest::INTERNAL, manifest,
+      Extension::Create(path, mojom::ManifestLocation::kInternal, manifest,
                         Extension::NO_FLAGS, &error));
   EXPECT_TRUE(extension.get()) << error;
   return extension;
diff --git a/extensions/common/extension_unittest.cc b/extensions/common/extension_unittest.cc
index 3734c038..82a0107b 100644
--- a/extensions/common/extension_unittest.cc
+++ b/extensions/common/extension_unittest.cc
@@ -14,6 +14,8 @@
 #include "extensions/common/value_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using extensions::mojom::ManifestLocation;
+
 namespace extensions {
 namespace {
 
@@ -24,8 +26,9 @@
     bool expect_warning = false,
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
   std::string error;
-  scoped_refptr<const Extension> extension = Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, *manifest, custom_flag, &error);
+  scoped_refptr<const Extension> extension =
+      Extension::Create(base::FilePath(), ManifestLocation::kInternal,
+                        *manifest, custom_flag, &error);
   if (!extension) {
     return testing::AssertionFailure()
            << "Extension creation failed: " << error;
@@ -61,8 +64,9 @@
     std::unique_ptr<base::DictionaryValue> manifest,
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
   std::string error;
-  scoped_refptr<const Extension> extension = Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, *manifest, custom_flag, &error);
+  scoped_refptr<const Extension> extension =
+      Extension::Create(base::FilePath(), ManifestLocation::kInternal,
+                        *manifest, custom_flag, &error);
   if (extension)
     return testing::AssertionFailure() << "Extension creation succeeded.";
 
@@ -71,7 +75,7 @@
 
 testing::AssertionResult RunCreationWithFlags(
     const base::DictionaryValue* manifest,
-    Manifest::Location location,
+    mojom::ManifestLocation location,
     Manifest::Type expected_type,
     Extension::InitFromValueFlags custom_flag = Extension::NO_FLAGS) {
   std::string error;
@@ -247,12 +251,12 @@
       .Set("manifest_version", 2);
   std::unique_ptr<base::DictionaryValue> manifest = builder.Build();
 
-  EXPECT_TRUE(RunCreationWithFlags(manifest.get(), Manifest::EXTERNAL_POLICY,
-                                   Manifest::TYPE_EXTENSION,
-                                   Extension::NO_FLAGS));
-  EXPECT_TRUE(RunCreationWithFlags(manifest.get(), Manifest::EXTERNAL_POLICY,
-                                   Manifest::TYPE_LOGIN_SCREEN_EXTENSION,
-                                   Extension::FOR_LOGIN_SCREEN));
+  EXPECT_TRUE(
+      RunCreationWithFlags(manifest.get(), ManifestLocation::kExternalPolicy,
+                           Manifest::TYPE_EXTENSION, Extension::NO_FLAGS));
+  EXPECT_TRUE(RunCreationWithFlags(
+      manifest.get(), ManifestLocation::kExternalPolicy,
+      Manifest::TYPE_LOGIN_SCREEN_EXTENSION, Extension::FOR_LOGIN_SCREEN));
 }
 
 }  // namespace extensions
diff --git a/extensions/common/features/simple_feature_unittest.cc b/extensions/common/features/simple_feature_unittest.cc
index e771b54..006bf73 100644
--- a/extensions/common/features/simple_feature_unittest.cc
+++ b/extensions/common/features/simple_feature_unittest.cc
@@ -330,9 +330,9 @@
   manifest.SetString("app.launch.local_path", "foo.html");
 
   std::string error;
-  scoped_refptr<const Extension> extension(Extension::Create(
-      base::FilePath(), Manifest::INTERNAL, manifest, Extension::NO_FLAGS,
-      &error));
+  scoped_refptr<const Extension> extension(
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                        manifest, Extension::NO_FLAGS, &error));
   EXPECT_EQ("", error);
   ASSERT_TRUE(extension.get());
 
@@ -437,8 +437,8 @@
 
   std::string error;
   scoped_refptr<const Extension> extension(
-      Extension::Create(base::FilePath(), Manifest::INTERNAL, manifest,
-                        Extension::NO_FLAGS, &error));
+      Extension::Create(base::FilePath(), mojom::ManifestLocation::kInternal,
+                        manifest, Extension::NO_FLAGS, &error));
   EXPECT_EQ("", error);
   ASSERT_TRUE(extension.get());
 
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc
index d4b82325..44bc0d33 100644
--- a/extensions/common/file_util.cc
+++ b/extensions/common/file_util.cc
@@ -234,7 +234,8 @@
   }
 
   scoped_refptr<Extension> extension(Extension::Create(
-      extension_path, location, *manifest, flags, extension_id, error));
+      extension_path, static_cast<mojom::ManifestLocation>(location), *manifest,
+      flags, extension_id, error));
   if (!extension.get())
     return nullptr;
 
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc
index 8726a472..1ead6017 100644
--- a/extensions/common/file_util_unittest.cc
+++ b/extensions/common/file_util_unittest.cc
@@ -48,7 +48,7 @@
 scoped_refptr<Extension> LoadExtensionManifest(
     const base::DictionaryValue& manifest,
     const base::FilePath& manifest_dir,
-    Manifest::Location location,
+    mojom::ManifestLocation location,
     int extra_flags,
     std::string* error) {
   scoped_refptr<Extension> extension =
@@ -59,7 +59,7 @@
 scoped_refptr<Extension> LoadExtensionManifest(
     const std::string& manifest_value,
     const base::FilePath& manifest_dir,
-    Manifest::Location location,
+    mojom::ManifestLocation location,
     int extra_flags,
     std::string* error) {
   JSONStringValueDeserializer deserializer(manifest_value);
@@ -363,7 +363,7 @@
       non_ascii_file.c_str());
   std::string error;
   scoped_refptr<Extension> extension = LoadExtensionManifest(
-      kManifest, temp.GetPath(), Manifest::UNPACKED, 0, &error);
+      kManifest, temp.GetPath(), mojom::ManifestLocation::kUnpacked, 0, &error);
   ASSERT_TRUE(extension.get()) << error;
 
   std::vector<InstallWarning> warnings;
@@ -388,7 +388,7 @@
   std::string error;
   std::vector<InstallWarning> warnings;
   scoped_refptr<Extension> extension = LoadExtensionManifest(
-      *value, temp.GetPath(), Manifest::UNPACKED, 0, &error);
+      *value, temp.GetPath(), mojom::ManifestLocation::kUnpacked, 0, &error);
   ASSERT_TRUE(extension.get()) << error;
 
   EXPECT_FALSE(
@@ -402,8 +402,8 @@
   scripts->Clear();
   scripts->AppendString("http://google.com/foo.js");
 
-  extension = LoadExtensionManifest(*value, temp.GetPath(), Manifest::UNPACKED,
-                                    0, &error);
+  extension = LoadExtensionManifest(
+      *value, temp.GetPath(), mojom::ManifestLocation::kUnpacked, 0, &error);
   ASSERT_TRUE(extension.get()) << error;
 
   warnings.clear();
diff --git a/extensions/common/manifest.cc b/extensions/common/manifest.cc
index 450f970..f447d8e 100644
--- a/extensions/common/manifest.cc
+++ b/extensions/common/manifest.cc
@@ -19,7 +19,6 @@
 #include "extensions/common/install_warning.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handler_helpers.h"
-#include "extensions/common/mojom/manifest.mojom-shared.h"
 
 namespace extensions {
 
@@ -265,13 +264,14 @@
 
 // static
 std::unique_ptr<Manifest> Manifest::CreateManifestForLoginScreen(
-    Location location,
+    mojom::ManifestLocation location,
     std::unique_ptr<base::DictionaryValue> value,
     ExtensionId extension_id) {
-  CHECK(IsPolicyLocation(location));
+  CHECK(IsPolicyLocation(static_cast<Location>(location)));
   // Use base::WrapUnique + new because the constructor is private.
-  return base::WrapUnique(
-      new Manifest(location, std::move(value), std::move(extension_id), true));
+  return base::WrapUnique(new Manifest(static_cast<Location>(location),
+                                       std::move(value),
+                                       std::move(extension_id), true));
 }
 
 Manifest::Manifest(Location location,
diff --git a/extensions/common/manifest.h b/extensions/common/manifest.h
index db9b562a..fead54f 100644
--- a/extensions/common/manifest.h
+++ b/extensions/common/manifest.h
@@ -16,6 +16,7 @@
 #include "base/values.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/hashed_extension_id.h"
+#include "extensions/common/mojom/manifest.mojom-shared.h"
 
 namespace extensions {
 struct InstallWarning;
@@ -144,7 +145,7 @@
   // result in a Manifest of TYPE_LOGIN_SCREEN_EXTENSION, since other items
   // (like platform apps) may be installed in the same login screen profile.
   static std::unique_ptr<Manifest> CreateManifestForLoginScreen(
-      Location location,
+      mojom::ManifestLocation location,
       std::unique_ptr<base::DictionaryValue> value,
       ExtensionId extension_id);
 
diff --git a/extensions/common/manifest_handler_unittest.cc b/extensions/common/manifest_handler_unittest.cc
index 20a7aaa9..623fc47 100644
--- a/extensions/common/manifest_handler_unittest.cc
+++ b/extensions/common/manifest_handler_unittest.cc
@@ -223,9 +223,9 @@
 
   // Succeeds when "a" is not recognized.
   std::string error;
-  scoped_refptr<Extension> extension =
-      Extension::Create(base::FilePath(), Manifest::INVALID_LOCATION,
-                        *manifest_a, Extension::NO_FLAGS, &error);
+  scoped_refptr<Extension> extension = Extension::Create(
+      base::FilePath(), mojom::ManifestLocation::kInvalidLocation, *manifest_a,
+      Extension::NO_FLAGS, &error);
   EXPECT_TRUE(extension.get());
 
   // Register a handler for "a" that fails.
@@ -235,12 +235,9 @@
       "A", SingleKey("a"), std::vector<std::string>(), &watcher));
   ManifestHandler::FinalizeRegistration();
 
-  extension = Extension::Create(
-      base::FilePath(),
-      Manifest::INVALID_LOCATION,
-      *manifest_a,
-      Extension::NO_FLAGS,
-      &error);
+  extension = Extension::Create(base::FilePath(),
+                                mojom::ManifestLocation::kInvalidLocation,
+                                *manifest_a, Extension::NO_FLAGS, &error);
   EXPECT_FALSE(extension.get());
   EXPECT_EQ("A", error);
 }
diff --git a/extensions/common/manifest_test.cc b/extensions/common/manifest_test.cc
index 1ad01bc..c10838c 100644
--- a/extensions/common/manifest_test.cc
+++ b/extensions/common/manifest_test.cc
@@ -116,9 +116,9 @@
   DCHECK(value.is_dict());
   const base::DictionaryValue* dictionary_manifest = nullptr;
   value.GetAsDictionary(&dictionary_manifest);
-  return Extension::Create(test_data_dir.DirName(), location,
-                           *dictionary_manifest, flags, GetTestExtensionID(),
-                           error);
+  return Extension::Create(
+      test_data_dir.DirName(), static_cast<mojom::ManifestLocation>(location),
+      *dictionary_manifest, flags, GetTestExtensionID(), error);
 }
 
 scoped_refptr<Extension> ManifestTest::LoadAndExpectSuccess(
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.cc b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
index e9d07b62..8425b294 100644
--- a/gpu/command_buffer/service/shared_image_backing_egl_image.cc
+++ b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
@@ -236,6 +236,8 @@
   }
 
   auto texture_holder = GenEGLImageSibling();
+  if (!texture_holder)
+    return nullptr;
   return std::make_unique<T>(manager, this, tracker, std::move(texture_holder));
 }
 
diff --git a/gpu/command_buffer/service/shared_image_representation_skia_gl.cc b/gpu/command_buffer/service/shared_image_representation_skia_gl.cc
index 5ab1f28..53b43c0 100644
--- a/gpu/command_buffer/service/shared_image_representation_skia_gl.cc
+++ b/gpu/command_buffer/service/shared_image_representation_skia_gl.cc
@@ -74,6 +74,8 @@
 SharedImageRepresentationSkiaGL::~SharedImageRepresentationSkiaGL() {
   DCHECK_EQ(RepresentationAccessMode::kNone, mode_);
   surface_.reset();
+  if (!has_context())
+    gl_representation_->OnContextLost();
 }
 
 sk_sp<SkSurface> SharedImageRepresentationSkiaGL::BeginWriteAccess(
diff --git a/gpu/gles2_conform_support/generate_gles2_conform_tests.py b/gpu/gles2_conform_support/generate_gles2_conform_tests.py
index 632864f..c29407c 100755
--- a/gpu/gles2_conform_support/generate_gles2_conform_tests.py
+++ b/gpu/gles2_conform_support/generate_gles2_conform_tests.py
@@ -52,7 +52,7 @@
     out_dir = '.'
 
   out_filename = os.path.join(out_dir, 'gles2_conform_test_autogen.cc')
-  with open(out_filename, 'w') as out_file:
+  with open(out_filename, 'wb') as out_file:
     GenerateTests(out_file)
 
   return 0
diff --git a/infra/config/generated/commit-queue.cfg b/infra/config/generated/commit-queue.cfg
index 3d7963b..64021156 100644
--- a/infra/config/generated/commit-queue.cfg
+++ b/infra/config/generated/commit-queue.cfg
@@ -294,6 +294,10 @@
         includable_only: true
       }
       builders {
+        name: "chromium/try/android-weblayer-pie-x86-rel-tests"
+        includable_only: true
+      }
+      builders {
         name: "chromium/try/android-weblayer-pie-x86-wpt-fyi-rel"
         includable_only: true
       }
@@ -1135,26 +1139,14 @@
         includable_only: true
       }
       builders {
-        name: "chromium/try/linux-swangle-try-tot-angle-x86"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/linux-swangle-try-tot-swiftshader-x64"
         includable_only: true
       }
       builders {
-        name: "chromium/try/linux-swangle-try-tot-swiftshader-x86"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/linux-swangle-try-x64"
         includable_only: true
       }
       builders {
-        name: "chromium/try/linux-swangle-try-x86"
-        includable_only: true
-      }
-      builders {
         name: "chromium/try/linux-trusty-rel"
         includable_only: true
       }
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 6a8ff7e..b25f75ef 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -24949,64 +24949,6 @@
       }
     }
     builders {
-      name: "linux-swangle-tot-angle-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.gpu.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.swangle\",\"recipe\":\"angle_chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.gtests_local"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-swangle-tot-swiftshader-x64"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -25065,64 +25007,6 @@
       }
     }
     builders {
-      name: "linux-swangle-tot-swiftshader-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.gpu.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.swangle\",\"recipe\":\"angle_chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.gtests_local"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-swangle-x64"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -25181,64 +25065,6 @@
       }
     }
     builders {
-      name: "linux-swangle-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.gpu.ci"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.swangle\",\"recipe\":\"chromium\"}"
-      execution_timeout_secs: 10800
-      build_numbers: YES
-      service_account: "chromium-ci-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.gtests_local"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "ci_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_ci_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-trusty-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -33395,6 +33221,71 @@
       }
     }
     builders {
+      name: "android-weblayer-pie-x86-rel-tests"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "pool:luci.chromium.try"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "recipes"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.android\",\"recipe\":\"chromium_trybot\"}"
+      execution_timeout_secs: 14400
+      expiration_secs: 7200
+      grace_period {
+        seconds: 120
+      }
+      caches {
+        name: "win_toolchain"
+        path: "win_toolchain"
+      }
+      build_numbers: YES
+      service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
+      task_template_canary_percentage {
+        value: 5
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink"
+        value: 100
+      }
+      experiments {
+        key: "chromium.resultdb.result_sink.junit_tests"
+        value: 100
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "try_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "gpu_try_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
+            }
+          }
+        }
+        history_options {
+          use_invocation_timestamp: true
+        }
+      }
+    }
+    builders {
       name: "android-weblayer-pie-x86-wpt-fyi-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -44281,68 +44172,6 @@
       }
     }
     builders {
-      name: "linux-swangle-try-tot-angle-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.swangle.linux.x86.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.swangle\",\"recipe\":\"angle_chromium_trybot\"}"
-      execution_timeout_secs: 7200
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-swangle-try-tot-swiftshader-x64"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -44405,68 +44234,6 @@
       }
     }
     builders {
-      name: "linux-swangle-try-tot-swiftshader-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.swangle.linux.x86.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.swangle\",\"recipe\":\"angle_chromium_trybot\"}"
-      execution_timeout_secs: 7200
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-swangle-try-x64"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
@@ -44529,68 +44296,6 @@
       }
     }
     builders {
-      name: "linux-swangle-try-x86"
-      swarming_host: "chromium-swarm.appspot.com"
-      swarming_tags: "vpython:native-python-wrapper"
-      dimensions: "builderless:1"
-      dimensions: "cores:8"
-      dimensions: "cpu:x86-64"
-      dimensions: "os:Ubuntu-16.04"
-      dimensions: "pool:luci.chromium.swangle.linux.x86.try"
-      dimensions: "ssd:0"
-      exe {
-        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
-        cipd_version: "refs/heads/master"
-        cmd: "recipes"
-      }
-      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"tryserver.chromium.swangle\",\"recipe\":\"chromium_trybot\"}"
-      execution_timeout_secs: 7200
-      expiration_secs: 7200
-      caches {
-        name: "win_toolchain"
-        path: "win_toolchain"
-      }
-      build_numbers: YES
-      service_account: "chromium-try-gpu-builder@chops-service-accounts.iam.gserviceaccount.com"
-      task_template_canary_percentage {
-        value: 5
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink"
-        value: 100
-      }
-      experiments {
-        key: "chromium.resultdb.result_sink.junit_tests"
-        value: 100
-      }
-      experiments {
-        key: "luci.use_realms"
-        value: 100
-      }
-      resultdb {
-        enable: true
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "try_test_results"
-          test_results {}
-        }
-        bq_exports {
-          project: "luci-resultdb"
-          dataset: "chromium"
-          table: "gpu_try_test_results"
-          test_results {
-            predicate {
-              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
-            }
-          }
-        }
-        history_options {
-          use_invocation_timestamp: true
-        }
-      }
-    }
-    builders {
       name: "linux-trusty-rel"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index e904bdc..542691b 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -9699,11 +9699,6 @@
     short_name: "x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/linux-swangle-x86"
-    category: "DEPS|Linux"
-    short_name: "x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/linux-swangle-x64"
     category: "DEPS|Linux"
     short_name: "x64"
@@ -9719,11 +9714,6 @@
     short_name: "x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/linux-swangle-tot-angle-x86"
-    category: "ToT ANGLE|Linux"
-    short_name: "x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/linux-swangle-tot-angle-x64"
     category: "ToT ANGLE|Linux"
     short_name: "x64"
@@ -9739,11 +9729,6 @@
     short_name: "x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/linux-swangle-tot-swiftshader-x86"
-    category: "ToT SwiftShader|Linux"
-    short_name: "x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/linux-swangle-tot-swiftshader-x64"
     category: "ToT SwiftShader|Linux"
     short_name: "x64"
@@ -12246,6 +12231,9 @@
     name: "buildbucket/luci.chromium.try/android-pie-x86-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-weblayer-pie-x86-rel-tests"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-weblayer-pie-x86-wpt-fyi-rel"
   }
   builders {
@@ -12762,21 +12750,12 @@
     name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-angle-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-angle-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-swiftshader-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-swiftshader-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-swangle-try-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-trusty-rel"
   }
   builders {
@@ -13228,6 +13207,9 @@
     name: "buildbucket/luci.chromium.try/android-pie-x86-rel"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/android-weblayer-pie-x86-rel-tests"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/android-weblayer-pie-x86-wpt-fyi-rel"
   }
   builders {
@@ -13931,21 +13913,12 @@
     name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-angle-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-angle-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-swiftshader-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-tot-swiftshader-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux-swangle-try-x64"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux-swangle-try-x86"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/mac-swangle-chromium-try-x64"
   }
   builders {
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 29f9679..2024062c 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -5670,16 +5670,6 @@
   }
 }
 job {
-  id: "linux-swangle-tot-angle-x86"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-swangle-tot-angle-x86"
-  }
-}
-job {
   id: "linux-swangle-tot-swiftshader-x64"
   realm: "ci"
   acl_sets: "ci"
@@ -5690,16 +5680,6 @@
   }
 }
 job {
-  id: "linux-swangle-tot-swiftshader-x86"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-swangle-tot-swiftshader-x86"
-  }
-}
-job {
   id: "linux-swangle-x64"
   realm: "ci"
   acl_sets: "ci"
@@ -5710,16 +5690,6 @@
   }
 }
 job {
-  id: "linux-swangle-x86"
-  realm: "ci"
-  acl_sets: "ci"
-  buildbucket {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-swangle-x86"
-  }
-}
-job {
   id: "linux-trusty-rel"
   realm: "ci"
   acl_sets: "ci"
@@ -7025,11 +6995,8 @@
   triggers: "linux-perfetto-rel"
   triggers: "linux-swangle-chromium-x64"
   triggers: "linux-swangle-tot-angle-x64"
-  triggers: "linux-swangle-tot-angle-x86"
   triggers: "linux-swangle-tot-swiftshader-x64"
-  triggers: "linux-swangle-tot-swiftshader-x86"
   triggers: "linux-swangle-x64"
-  triggers: "linux-swangle-x86"
   triggers: "linux-trusty-rel"
   triggers: "linux-ubsan-vptr"
   triggers: "linux-upload-perfetto"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index ca70122..1530699 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -5663,14 +5663,6 @@
 )
 
 ci.swangle_linux_builder(
-    name = "linux-swangle-tot-angle-x86",
-    console_view_entry = consoles.console_view_entry(
-        category = "ToT ANGLE|Linux",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_linux_builder(
     name = "linux-swangle-tot-swiftshader-x64",
     console_view_entry = consoles.console_view_entry(
         category = "ToT SwiftShader|Linux",
@@ -5679,14 +5671,6 @@
 )
 
 ci.swangle_linux_builder(
-    name = "linux-swangle-tot-swiftshader-x86",
-    console_view_entry = consoles.console_view_entry(
-        category = "ToT SwiftShader|Linux",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_linux_builder(
     name = "linux-swangle-x64",
     console_view_entry = consoles.console_view_entry(
         category = "DEPS|Linux",
@@ -5695,15 +5679,6 @@
     pinned = False,
 )
 
-ci.swangle_linux_builder(
-    name = "linux-swangle-x86",
-    console_view_entry = consoles.console_view_entry(
-        category = "DEPS|Linux",
-        short_name = "x86",
-    ),
-    pinned = False,
-)
-
 ci.swangle_mac_builder(
     name = "mac-swangle-chromium-x64",
     console_view_entry = consoles.console_view_entry(
diff --git a/infra/config/subprojects/chromium/swangle.try.star b/infra/config/subprojects/chromium/swangle.try.star
index 70d9432..92a31083 100644
--- a/infra/config/subprojects/chromium/swangle.try.star
+++ b/infra/config/subprojects/chromium/swangle.try.star
@@ -44,32 +44,16 @@
 )
 
 try_.chromium_swangle_linux_builder(
-    name = "linux-swangle-try-tot-angle-x86",
-    pool = "luci.chromium.swangle.linux.x86.try",
-)
-
-try_.chromium_swangle_linux_builder(
     name = "linux-swangle-try-tot-swiftshader-x64",
     pool = "luci.chromium.swangle.sws.linux.x64.try",
 )
 
 try_.chromium_swangle_linux_builder(
-    name = "linux-swangle-try-tot-swiftshader-x86",
-    pool = "luci.chromium.swangle.linux.x86.try",
-)
-
-try_.chromium_swangle_linux_builder(
     name = "linux-swangle-try-x64",
     pool = "luci.chromium.swangle.deps.linux.x64.try",
     pinned = False,
 )
 
-try_.chromium_swangle_linux_builder(
-    name = "linux-swangle-try-x86",
-    pool = "luci.chromium.swangle.linux.x86.try",
-    pinned = False,
-)
-
 try_.chromium_swangle_mac_builder(
     name = "mac-swangle-chromium-try-x64",
     pool = "luci.chromium.swangle.chromium.mac.x64.try",
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index ad167fe2..02ebf9e 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -472,6 +472,10 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-weblayer-pie-x86-rel-tests",
+)
+
+try_.chromium_android_builder(
     name = "android-weblayer-pie-x86-wpt-fyi-rel",
 )
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h
index 67a1bdd..58ef688a 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h
@@ -78,6 +78,9 @@
 // Returns nil if there is no empty item for this section.
 - (NSIndexPath*)addEmptyItemForSection:(NSInteger)section;
 
+// Returns whether |section| contains the Return to Recent Tab tile.
+- (BOOL)isReturnToRecentTabSection:(NSInteger)section;
+
 // Returns whether |section| contains the Most Visited tiles.
 - (BOOL)isMostVisitedSection:(NSInteger)section;
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index c7ed780..6924ead6 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -582,6 +582,12 @@
   return [self addItem:item toSectionWithIdentifier:sectionIdentifier];
 }
 
+- (BOOL)isReturnToRecentTabSection:(NSInteger)section {
+  return [self.collectionViewController.collectionViewModel
+             sectionIdentifierForSection:section] ==
+         SectionIdentifierReturnToRecentTab;
+}
+
 - (BOOL)isMostVisitedSection:(NSInteger)section {
   return
       [self.collectionViewController.collectionViewModel
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
index 5a545ac..d51f7ac 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
@@ -13,6 +13,9 @@
 
 extern const CGFloat kHintTextScale;
 
+// Bottom margin for the Return to Recent Tab tile.
+extern const CGFloat kReturnToRecentTabSectionBottomMargin;
+
 // Returns the proper height for the doodle. |logoIsShowing| is YES if showing
 // the Google logo. |doodleisShowing| is YES if the doodle is showing. The
 // SizeClass of the |traitCollection| of the view displaying the doodle is used
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index c3db003..03a6f10 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -34,7 +34,7 @@
 // Top margin for the doodle.
 const CGFloat kDoodleTopMarginRegularXRegular = 162;
 const CGFloat kDoodleTopMarginOther = 48;
-const CGFloat kShrunkDoodleTopMarginOther = 84;
+const CGFloat kShrunkDoodleTopMarginOther = 65;
 // Size of the doodle top margin which is multiplied by the scaled font factor,
 // and added to |kDoodleTopMarginOther| on non Regular x Regular form factors.
 const CGFloat kDoodleScaledTopMarginOther = 10;
@@ -45,6 +45,7 @@
 
 // Bottom margin for the search field.
 const CGFloat kNTPSearchFieldBottomPadding = 18;
+const CGFloat kNTPShrunkLogoSearchFieldBottomPadding = 20;
 
 const CGFloat kTopSpacingMaterial = 24;
 
@@ -67,6 +68,7 @@
 
 const int kSearchFieldBackgroundColor = 0xF1F3F4;
 const CGFloat kHintTextScale = 0.15;
+const CGFloat kReturnToRecentTabSectionBottomMargin = 25;
 
 CGFloat doodleHeight(BOOL logoIsShowing,
                      BOOL doodleIsShowing,
@@ -125,13 +127,16 @@
                             BOOL toolbarPresent,
                             CGFloat topInset,
                             UITraitCollection* traitCollection) {
+  CGFloat bottomPadding = ShouldShowReturnToMostRecentTabForStartSurface()
+                              ? kNTPShrunkLogoSearchFieldBottomPadding
+                              : kNTPSearchFieldBottomPadding;
   CGFloat headerHeight =
       doodleTopMargin(toolbarPresent, topInset, traitCollection) +
       doodleHeight(logoIsShowing, doodleIsShowing, traitCollection) +
       searchFieldTopMargin() +
       ToolbarExpandedHeight(
           [UIApplication sharedApplication].preferredContentSizeCategory) +
-      kNTPSearchFieldBottomPadding;
+      bottomPadding;
   if (!IsRegularXRegularSizeClass(traitCollection)) {
     return headerHeight;
   }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
index daccb2b2..fd82e584 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
@@ -201,7 +201,7 @@
       doodleTopMargin(YES, kTopInset, IPhonePortraitTraitCollection());
   EXPECT_EQ(68, heightLogoPortrait);
   EXPECT_EQ(60, heightNoLogoPortrait);
-  EXPECT_EQ(114, topMarginPortrait);
+  EXPECT_EQ(95, topMarginPortrait);
 }
 
 }  // namespace content_suggestions
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index cfdc765a..57be3f3 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -105,9 +105,8 @@
     ThemeChangeDelegate,
     URLDropDelegate> {
   // Observer bridge for mediator to listen to
-  // StartSurfaceRecentTabRemovalObserverBridge.
-  std::unique_ptr<StartSurfaceRecentTabRemovalObserverBridge>
-      _startSurfaceObserver;
+  // StartSurfaceRecentTabObserverBridge.
+  std::unique_ptr<StartSurfaceRecentTabObserverBridge> _startSurfaceObserver;
 }
 
 @property(nonatomic, strong)
@@ -748,7 +747,7 @@
         configureMostRecentTabItemWithWebState:most_recent_tab];
     if (!_startSurfaceObserver) {
       _startSurfaceObserver =
-          std::make_unique<StartSurfaceRecentTabRemovalObserverBridge>(
+          std::make_unique<StartSurfaceRecentTabObserverBridge>(
               self.contentSuggestionsMediator);
       StartSurfaceRecentTabBrowserAgent::FromBrowser(self.browser)
           ->AddObserver(_startSurfaceObserver.get());
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
index 865f924..e62ea40 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h
@@ -50,7 +50,7 @@
 @interface ContentSuggestionsMediator
     : NSObject <ContentSuggestionsDataSource,
                 ContentSuggestionsMetricsRecorderDelegate,
-                StartSurfaceRecentTabRemovalObserving>
+                StartSurfaceRecentTabObserving>
 
 // Initialize the mediator with the |contentService| to mediate.
 - (instancetype)
@@ -115,6 +115,10 @@
 // Get the maximum number of sites shown.
 + (NSUInteger)maxSitesShown;
 
+// Whether the most recent tab tile is being shown. Returns YES if
+// configureMostRecentTabItemWithWebState: has been called.
+- (BOOL)mostRecentTabStartSurfaceTileIsShowing;
+
 // Configures the most recent tab item for |webState|.
 - (void)configureMostRecentTabItemWithWebState:(web::WebState*)webState;
 
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
index 1fed49b..37cf42a0 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.mm
@@ -150,8 +150,9 @@
 @property(nonatomic, strong) ContentSuggestionsDiscoverItem* discoverItem;
 // Number of unread items in reading list model.
 @property(nonatomic, assign) NSInteger readingListUnreadCount;
-// Whether to show the most recent tab tile.
-@property(nonatomic, assign) BOOL showMostRecentTabStartSurfaceTile;
+// YES if the Return to Recent Tab tile is being shown.
+@property(nonatomic, assign, getter=mostRecentTabStartSurfaceTileIsShowing)
+    BOOL showMostRecentTabStartSurfaceTile;
 // Whether the incognito mode is available.
 @property(nonatomic, assign) BOOL incognitoAvailable;
 
@@ -296,6 +297,9 @@
       self.returnToRecentTabItem.icon = favicon.ToUIImage();
     }
   }
+  if (!self.returnToRecentTabItem.icon) {
+    driver->FetchFavicon(webState->GetLastCommittedURL(), false);
+  }
 
   self.returnToRecentTabItem.title =
       l10n_util::GetNSString(IDS_IOS_RETURN_TO_RECENT_TAB_TITLE);
@@ -313,13 +317,20 @@
   [self.dataSink clearSection:self.returnToRecentTabSectionInfo];
 }
 
-#pragma mark - StartSurfaceRecentTabRemovalObserving
+#pragma mark - StartSurfaceRecentTabObserving
 
 - (void)mostRecentTabWasRemoved:(web::WebState*)web_state {
   DCHECK(IsStartSurfaceEnabled());
   [self hideRecentTabTile];
 }
 
+- (void)mostRecentTabFaviconUpdatedWithImage:(UIImage*)image {
+  if (self.returnToRecentTabItem) {
+    self.returnToRecentTabItem.icon = image;
+    [self.dataSink itemHasChanged:self.returnToRecentTabItem];
+  }
+}
+
 #pragma mark - ContentSuggestionsDataSource
 
 - (NSArray<ContentSuggestionsSectionInformation*>*)sectionsInfo {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 3cf99cc..8060cd3 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -590,6 +590,16 @@
     parentInset.top = 0;
     parentInset.left = 0;
     parentInset.right = 0;
+  } else if ([self.collectionUpdater isReturnToRecentTabSection:section]) {
+    CGFloat collectionWidth = collectionView.bounds.size.width;
+    CGFloat maxCardWidth = content_suggestions::searchFieldWidth(
+        collectionWidth, self.traitCollection);
+    CGFloat margin =
+        MAX(0, (collectionView.frame.size.width - maxCardWidth) / 2);
+    parentInset.left = margin;
+    parentInset.right = margin;
+    parentInset.bottom =
+        content_suggestions::kReturnToRecentTabSectionBottomMargin;
   } else if ([self.collectionUpdater isMostVisitedSection:section] ||
              [self.collectionUpdater isPromoSection:section]) {
     CGFloat margin = CenteredTilesMarginForWidth(
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
index 07d5eac0..452d347 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -35,6 +35,8 @@
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_return_to_recent_tab_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_alert_factory.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.h"
+#import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_mediator.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_metrics_recorder.h"
@@ -678,6 +680,18 @@
           : self.suggestionsViewController.collectionView;
   UIEdgeInsets contentInset = collectionView.contentInset;
   CGPoint contentOffset = collectionView.contentOffset;
+  if ([self.suggestionsMediator mostRecentTabStartSurfaceTileIsShowing]) {
+    // Return to Recent tab tile is only shown one time, so subtract it's
+    // vertical space to preserve relative scroll position from top.
+    CGFloat tileSectionHeight =
+        [ContentSuggestionsReturnToRecentTabCell defaultSize].height +
+        content_suggestions::kReturnToRecentTabSectionBottomMargin;
+    if (contentOffset.y >
+        tileSectionHeight +
+            [self.headerCollectionInteractionHandler pinnedOffsetY]) {
+      contentOffset.y -= tileSectionHeight;
+    }
+  }
 
   contentOffset.y -=
       self.headerCollectionInteractionHandler.collectionShiftingOffset;
diff --git a/ios/chrome/browser/ui/start_surface/BUILD.gn b/ios/chrome/browser/ui/start_surface/BUILD.gn
index 28920a58..b96b7e2 100644
--- a/ios/chrome/browser/ui/start_surface/BUILD.gn
+++ b/ios/chrome/browser/ui/start_surface/BUILD.gn
@@ -33,9 +33,12 @@
   deps = [
     ":feature_flags",
     "//base",
+    "//components/favicon/ios",
     "//ios/chrome/browser/ui/main:browser_interface_provider",
     "//ios/chrome/browser/ui/main:observing_scene_agent",
     "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/web_state_list",
+    "//ios/web/public",
+    "//ios/web/public:web_state_observer",
   ]
 }
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
index 75e4f39..a8a80f62 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h
@@ -6,6 +6,8 @@
 #define IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_RECENT_TAB_BROWSER_AGENT_H_
 
 #include "base/observer_list.h"
+#include "base/scoped_observation.h"
+#include "components/favicon/ios/web_favicon_driver.h"
 #include "ios/chrome/browser/main/browser_observer.h"
 #import "ios/chrome/browser/main/browser_user_data.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
@@ -16,38 +18,42 @@
 
 class Browser;
 
-// Interface for listening to the removal of the most recent tab.
-class StartSurfaceRecentTabRemovalObserver {
+// Interface for listening to updates to the most recent tab.
+class StartSurfaceRecentTabObserver {
  public:
-  StartSurfaceRecentTabRemovalObserver() {}
+  StartSurfaceRecentTabObserver() {}
 
   // Not copyable or moveable.
-  StartSurfaceRecentTabRemovalObserver(
-      const StartSurfaceRecentTabRemovalObserver&) = delete;
-  StartSurfaceRecentTabRemovalObserver& operator=(
-      const StartSurfaceRecentTabRemovalObserver&) = delete;
+  StartSurfaceRecentTabObserver(const StartSurfaceRecentTabObserver&) = delete;
+  StartSurfaceRecentTabObserver& operator=(
+      const StartSurfaceRecentTabObserver&) = delete;
 
   // Notifies the receiver that the most recent tab was removed.
   virtual void MostRecentTabRemoved(web::WebState* web_state) {}
+  // Notifies the receiver that the favicon for the current page of the most
+  // recent tab was updated to |image|.
+  virtual void MostRecentTabFaviconUpdated(UIImage* image) {}
 
  protected:
-  virtual ~StartSurfaceRecentTabRemovalObserver() = default;
+  virtual ~StartSurfaceRecentTabObserver() = default;
 };
 
 // Browser Agent that manages the most recent WebState for the Start Surface and
-// listens to WebStateListObserver for instances of that WebState's removal.
+// listens to WebStateListObserver for instances of that WebState's removal and
+// updates to the current page's favicon for that WebState.
 class StartSurfaceRecentTabBrowserAgent
     : public BrowserUserData<StartSurfaceRecentTabBrowserAgent>,
       BrowserObserver,
-      public WebStateListObserver {
+      public WebStateListObserver,
+      public favicon::FaviconDriverObserver {
  public:
   // Notifies the Browser Agent to save the most recent WebState.
   void SaveMostRecentTab();
   // Returns the most recent WebState.
   web::WebState* most_recent_tab() { return most_recent_tab_; }
   // Add/Remove observers for this Browser Agent.
-  void AddObserver(StartSurfaceRecentTabRemovalObserver* observer);
-  void RemoveObserver(StartSurfaceRecentTabRemovalObserver* observer);
+  void AddObserver(StartSurfaceRecentTabObserver* observer);
+  void RemoveObserver(StartSurfaceRecentTabObserver* observer);
 
   ~StartSurfaceRecentTabBrowserAgent() override;
 
@@ -71,10 +77,20 @@
                           web::WebState* web_state,
                           int index) override;
 
+  // favicon::FaviconDriverObserver
+  void OnFaviconUpdated(favicon::FaviconDriver* driver,
+                        NotificationIconType notification_icon_type,
+                        const GURL& icon_url,
+                        bool icon_url_changed,
+                        const gfx::Image& image) override;
+
   // A list of observers notified when the most recent tab is removed. Weak
   // references.
-  base::ObserverList<StartSurfaceRecentTabRemovalObserver, true>::Unchecked
-      observers_;
+  base::ObserverList<StartSurfaceRecentTabObserver, true>::Unchecked observers_;
+  // Manages observation relationship between |this| and WebFaviconDriver.
+  base::ScopedObservation<favicon::FaviconDriver,
+                          favicon::FaviconDriverObserver>
+      favicon_driver_observer_{this};
   // The most recent tab managed by this Browser Agent.
   web::WebState* most_recent_tab_ = nullptr;
   // Browser.
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.mm b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.mm
index b055a56..ba4b1c1 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.mm
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.mm
@@ -18,7 +18,7 @@
 
 StartSurfaceRecentTabBrowserAgent::StartSurfaceRecentTabBrowserAgent(
     Browser* browser)
-    : browser_(browser) {
+    : favicon_driver_observer_(this), browser_(browser) {
   browser_->AddObserver(this);
   browser_->GetWebStateList()->AddObserver(this);
 }
@@ -30,16 +30,19 @@
 
 void StartSurfaceRecentTabBrowserAgent::SaveMostRecentTab() {
   most_recent_tab_ = browser_->GetWebStateList()->GetActiveWebState();
+  DCHECK(favicon::WebFaviconDriver::FromWebState(most_recent_tab_));
+  favicon_driver_observer_.Observe(
+      favicon::WebFaviconDriver::FromWebState(most_recent_tab_));
 }
 
 void StartSurfaceRecentTabBrowserAgent::AddObserver(
-    StartSurfaceRecentTabRemovalObserver* observer) {
+    StartSurfaceRecentTabObserver* observer) {
   DCHECK(!observers_.HasObserver(observer));
   observers_.AddObserver(observer);
 }
 
 void StartSurfaceRecentTabBrowserAgent::RemoveObserver(
-    StartSurfaceRecentTabRemovalObserver* observer) {
+    StartSurfaceRecentTabObserver* observer) {
   observers_.RemoveObserver(observer);
 }
 
@@ -68,3 +71,19 @@
     return;
   }
 }
+
+void StartSurfaceRecentTabBrowserAgent::OnFaviconUpdated(
+    favicon::FaviconDriver* driver,
+    NotificationIconType notification_icon_type,
+    const GURL& icon_url,
+    bool icon_url_changed,
+    const gfx::Image& image) {
+  if (driver->FaviconIsValid()) {
+    gfx::Image favicon = driver->GetFavicon();
+    if (!favicon.IsEmpty()) {
+      for (auto& observer : observers_) {
+        observer.MostRecentTabFaviconUpdated(image.ToUIImage());
+      }
+    }
+  }
+}
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
index f2859d4..802048b 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.h
@@ -13,34 +13,38 @@
 class WebState;
 }  // namespace web
 
-// Protocol that corresponds to StartSurfaceRecentTabRemovalObserver API. Allows
-// registering Objective-C objects to listen to removal of the most recent tab.
-@protocol StartSurfaceRecentTabRemovalObserving <NSObject>
+// Protocol that corresponds to StartSurfaceRecentTabObserver API. Allows
+// registering Objective-C objects to listen to updates to the most recent tab.
+@protocol StartSurfaceRecentTabObserving <NSObject>
 @optional
 // Notifies the receiver that the most recent tab was removed.
 - (void)mostRecentTabWasRemoved:(web::WebState*)web_state;
+// Notifies the receiver that the favicon for the current page of the most
+// recent tab was updated with |image|.
+- (void)mostRecentTabFaviconUpdatedWithImage:(UIImage*)image;
 @end
 
-// Bridge to use an id<StartSurfaceRecentTabRemovalObserving> as a
-// StartSurfaceRecentTabRemovalObserver.
-class StartSurfaceRecentTabRemovalObserverBridge
-    : public StartSurfaceRecentTabRemovalObserver {
+// Bridge to use an id<StartSurfaceRecentTabObserving> as a
+// StartSurfaceRecentTabObserver.
+class StartSurfaceRecentTabObserverBridge
+    : public StartSurfaceRecentTabObserver {
  public:
-  StartSurfaceRecentTabRemovalObserverBridge(
-      id<StartSurfaceRecentTabRemovalObserving> delegate);
-  ~StartSurfaceRecentTabRemovalObserverBridge() override;
+  StartSurfaceRecentTabObserverBridge(
+      id<StartSurfaceRecentTabObserving> delegate);
+  ~StartSurfaceRecentTabObserverBridge() override;
 
   // Not copyable or moveable.
-  StartSurfaceRecentTabRemovalObserverBridge(
-      const StartSurfaceRecentTabRemovalObserverBridge&) = delete;
-  StartSurfaceRecentTabRemovalObserverBridge& operator=(
-      const StartSurfaceRecentTabRemovalObserverBridge&) = delete;
+  StartSurfaceRecentTabObserverBridge(
+      const StartSurfaceRecentTabObserverBridge&) = delete;
+  StartSurfaceRecentTabObserverBridge& operator=(
+      const StartSurfaceRecentTabObserverBridge&) = delete;
 
  private:
   // StartSurfaceBrowserAgentObserver.
   void MostRecentTabRemoved(web::WebState* web_state) override;
+  void MostRecentTabFaviconUpdated(UIImage* image) override;
 
-  __weak id<StartSurfaceRecentTabRemovalObserving> delegate_ = nil;
+  __weak id<StartSurfaceRecentTabObserving> delegate_ = nil;
 };
 
 #endif  // IOS_CHROME_BROWSER_UI_START_SURFACE_START_SURFACE_RECENT_TAB_REMOVAL_OBSERVER_BRIDGE_H_
diff --git a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.mm b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.mm
index b26dc032..b1e26a7 100644
--- a/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.mm
+++ b/ios/chrome/browser/ui/start_surface/start_surface_recent_tab_removal_observer_bridge.mm
@@ -8,15 +8,14 @@
 #error "This file requires ARC support."
 #endif
 
-StartSurfaceRecentTabRemovalObserverBridge::
-    StartSurfaceRecentTabRemovalObserverBridge(
-        id<StartSurfaceRecentTabRemovalObserving> delegate)
+StartSurfaceRecentTabObserverBridge::StartSurfaceRecentTabObserverBridge(
+    id<StartSurfaceRecentTabObserving> delegate)
     : delegate_(delegate) {}
 
-StartSurfaceRecentTabRemovalObserverBridge::
-    ~StartSurfaceRecentTabRemovalObserverBridge() = default;
+StartSurfaceRecentTabObserverBridge::~StartSurfaceRecentTabObserverBridge() =
+    default;
 
-void StartSurfaceRecentTabRemovalObserverBridge::MostRecentTabRemoved(
+void StartSurfaceRecentTabObserverBridge::MostRecentTabRemoved(
     web::WebState* web_state) {
   const SEL selector = @selector(mostRecentTabWasRemoved:);
   if (![delegate_ respondsToSelector:selector])
@@ -24,3 +23,12 @@
 
   [delegate_ mostRecentTabWasRemoved:web_state];
 }
+
+void StartSurfaceRecentTabObserverBridge::MostRecentTabFaviconUpdated(
+    UIImage* image) {
+  const SEL selector = @selector(mostRecentTabFaviconUpdatedWithImage:);
+  if (![delegate_ respondsToSelector:selector])
+    return;
+
+  [delegate_ mostRecentTabFaviconUpdatedWithImage:image];
+}
diff --git a/ios/google_internal/frameworks/OWNERS b/ios/google_internal/frameworks/OWNERS
new file mode 100644
index 0000000..47b4de9
--- /dev/null
+++ b/ios/google_internal/frameworks/OWNERS
@@ -0,0 +1 @@
+bling-autoroll-builder@chops-service-accounts.iam.gserviceaccount.com
diff --git a/ios/web_view/internal/cwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
index 6a8eecd5..80d04c9 100644
--- a/ios/web_view/internal/cwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.mm
@@ -156,6 +156,7 @@
 @end
 
 namespace {
+NSString* gCustomUserAgent = nil;
 NSString* gUserAgentProduct = nil;
 BOOL gChromeLongPressAndForceTouchHandlingEnabled = YES;
 }  // namespace
@@ -193,6 +194,14 @@
   gChromeLongPressAndForceTouchHandlingEnabled = newValue;
 }
 
++ (NSString*)customUserAgent {
+  return gCustomUserAgent;
+}
+
++ (void)setCustomUserAgent:(NSString*)customUserAgent {
+  gCustomUserAgent = [customUserAgent copy];
+}
+
 + (NSString*)userAgentProduct {
   return gUserAgentProduct;
 }
diff --git a/ios/web_view/internal/cwv_web_view_unittest.mm b/ios/web_view/internal/cwv_web_view_unittest.mm
index b117104..8039c1cb 100644
--- a/ios/web_view/internal/cwv_web_view_unittest.mm
+++ b/ios/web_view/internal/cwv_web_view_unittest.mm
@@ -30,6 +30,13 @@
   web::ScopedTestingWebClient web_client_;
 };
 
+// Test +[CWVWebView customUserAgent].
+TEST_F(CWVWebViewTest, CustomUserAgent) {
+  EXPECT_FALSE(CWVWebView.customUserAgent);
+  CWVWebView.customUserAgent = @"FooCustomUserAgent";
+  EXPECT_NSEQ(@"FooCustomUserAgent", CWVWebView.customUserAgent);
+}
+
 // Test CWVWebView's inputAccessoryView controls whether or not the overriding
 // behavior is enabled.
 TEST_F(CWVWebViewTest, InputAccessoryView) {
diff --git a/ios/web_view/internal/web_view_web_client.mm b/ios/web_view/internal/web_view_web_client.mm
index cd698f6..99631861 100644
--- a/ios/web_view/internal/web_view_web_client.mm
+++ b/ios/web_view/internal/web_view_web_client.mm
@@ -72,8 +72,12 @@
 }
 
 std::string WebViewWebClient::GetUserAgent(web::UserAgentType type) const {
-  return web::BuildMobileUserAgent(
-      base::SysNSStringToUTF8([CWVWebView userAgentProduct]));
+  if (CWVWebView.customUserAgent) {
+    return base::SysNSStringToUTF8(CWVWebView.customUserAgent);
+  } else {
+    return web::BuildMobileUserAgent(
+        base::SysNSStringToUTF8([CWVWebView userAgentProduct]));
+  }
 }
 
 base::StringPiece WebViewWebClient::GetDataResource(
diff --git a/ios/web_view/internal/web_view_web_client_unittest.mm b/ios/web_view/internal/web_view_web_client_unittest.mm
index fbb09dd..7eb35e73 100644
--- a/ios/web_view/internal/web_view_web_client_unittest.mm
+++ b/ios/web_view/internal/web_view_web_client_unittest.mm
@@ -4,12 +4,16 @@
 
 #include "ios/web_view/internal/web_view_web_client.h"
 
+#include "ios/web/common/user_agent.h"
 #import "ios/web/common/web_view_creation_util.h"
 #import "ios/web/public/test/js_test_util.h"
 #include "ios/web/public/test/scoped_testing_web_client.h"
 #include "ios/web/public/test/web_test.h"
+#import "ios/web_view/internal/cwv_web_view_internal.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+#include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -19,8 +23,15 @@
 
 class WebViewWebClientTest : public web::WebTest {
  public:
-  WebViewWebClientTest() {}
-  ~WebViewWebClientTest() override = default;
+  WebViewWebClientTest() : web::WebTest(std::make_unique<WebViewWebClient>()) {
+    l10n_util::OverrideLocaleWithCocoaLocale();
+    ui::ResourceBundle::InitSharedInstanceWithLocale(
+        l10n_util::GetLocaleOverride(), /*delegate=*/nullptr,
+        ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);
+  }
+  ~WebViewWebClientTest() override {
+    ui::ResourceBundle::CleanupSharedInstance();
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebViewWebClientTest);
@@ -44,4 +55,45 @@
                              web_view, @"typeof __gCrWeb.autofill"));
 }
 
+// Tests that WebViewWebClientTest's GetUserAgent is configured by CWVWebView.
+TEST_F(WebViewWebClientTest, GetUserAgent) {
+  web::WebClient* web_client = GetWebClient();
+
+  // Test user agent when neither nor CWVWebView.userAgentProduct
+  // CWVWebView.customUserAgent have been set.
+  std::string user_agent_with_empty_product = web::BuildMobileUserAgent("");
+  EXPECT_EQ(user_agent_with_empty_product,
+            web_client->GetUserAgent(web::UserAgentType::NONE));
+  EXPECT_EQ(user_agent_with_empty_product,
+            web_client->GetUserAgent(web::UserAgentType::AUTOMATIC));
+  EXPECT_EQ(user_agent_with_empty_product,
+            web_client->GetUserAgent(web::UserAgentType::MOBILE));
+  EXPECT_EQ(user_agent_with_empty_product,
+            web_client->GetUserAgent(web::UserAgentType::DESKTOP));
+
+  // Test user agent when only CWVWebView.userAgentProduct is set.
+  [CWVWebView setUserAgentProduct:@"FooProduct"];
+  std::string user_agent_with_product = web::BuildMobileUserAgent("FooProduct");
+  EXPECT_EQ(user_agent_with_product,
+            web_client->GetUserAgent(web::UserAgentType::NONE));
+  EXPECT_EQ(user_agent_with_product,
+            web_client->GetUserAgent(web::UserAgentType::AUTOMATIC));
+  EXPECT_EQ(user_agent_with_product,
+            web_client->GetUserAgent(web::UserAgentType::MOBILE));
+  EXPECT_EQ(user_agent_with_product,
+            web_client->GetUserAgent(web::UserAgentType::DESKTOP));
+
+  // Test user agent when both CWVWebView.customUserAgent and
+  // CWVWebView.userAgentProduct are set.
+  CWVWebView.customUserAgent = @"FooCustomUserAgent";
+  EXPECT_EQ("FooCustomUserAgent",
+            web_client->GetUserAgent(web::UserAgentType::NONE));
+  EXPECT_EQ("FooCustomUserAgent",
+            web_client->GetUserAgent(web::UserAgentType::AUTOMATIC));
+  EXPECT_EQ("FooCustomUserAgent",
+            web_client->GetUserAgent(web::UserAgentType::MOBILE));
+  EXPECT_EQ("FooCustomUserAgent",
+            web_client->GetUserAgent(web::UserAgentType::DESKTOP));
+}
+
 }  // namespace ios_web_view
diff --git a/ios/web_view/public/cwv_defines.h b/ios/web_view/public/cwv_defines.h
index 8867cbf..a6e904b3 100644
--- a/ios/web_view/public/cwv_defines.h
+++ b/ios/web_view/public/cwv_defines.h
@@ -24,4 +24,7 @@
 // Allows customization of the keyboard input accessory view for CWVWebView.
 #define IOS_WEB_VIEW_SUPPORTS_CWV_WEB_VIEW_INPUT_ACCESSORY_VIEW 1
 
+// Allows customization of CWVWebView's user agent string.
+#define IOS_WEB_VIEW_SUPPORTS_CWV_WEB_VIEW_CUSTOM_USER_AGENT 1
+
 #endif  // IOS_WEB_VIEW_PUBLIC_CWV_DEFINES_H_
diff --git a/ios/web_view/public/cwv_web_view.h b/ios/web_view/public/cwv_web_view.h
index 3837455..0ae7e7d 100644
--- a/ios/web_view/public/cwv_web_view.h
+++ b/ios/web_view/public/cwv_web_view.h
@@ -142,7 +142,13 @@
 // https://developer.apple.com/documentation/uikit/uiresponder/1621119-inputaccessoryview?language=objc
 @property(nonatomic, strong, nullable) UIView* inputAccessoryView;
 
+// Allows full customization of the user agent.
+// Similar to -[WKWebView customUserAgent], but applies to all instances.
+// If non-nil, this is used instead of |userAgentProduct|.
+@property(nonatomic, class, copy, nullable) NSString* customUserAgent;
+
 // The User Agent product string used to build the full User Agent.
+// Deprecated. Use |customUserAgent| instead.
 + (NSString*)userAgentProduct;
 
 // Customizes the User Agent string by inserting |product|. It should be of the
@@ -155,6 +161,8 @@
 // Setting |product| is only guaranteed to affect web views which have not yet
 // been initialized. However, exisiting web views could also be affected
 // depending upon their internal state.
+//
+// Deprecated. Use |customUserAgent| instead.
 + (void)setUserAgentProduct:(NSString*)product;
 
 // Use this method to set the necessary credentials used to communicate with
diff --git a/ios/web_view/test/web_view_inttest.mm b/ios/web_view/test/web_view_inttest.mm
index 9af25f1e..41cf33f 100644
--- a/ios/web_view/test/web_view_inttest.mm
+++ b/ios/web_view/test/web_view_inttest.mm
@@ -51,6 +51,31 @@
   std::unique_ptr<net::test_server::HttpRequest> last_request_;
 };
 
+// Tests +[CWVWebView customUserAgent].
+TEST_F(WebViewTest, CustomUserAgent) {
+  ASSERT_TRUE(test_server_->Start());
+
+  CWVWebView.customUserAgent = @"FooCustomUserAgent";
+  ASSERT_NSEQ(@"FooCustomUserAgent", CWVWebView.customUserAgent);
+
+  // Cannot use existing |web_view_| here because the change above may only
+  // affect web views created after the change.
+  CWVWebView* web_view = test::CreateWebView();
+  GURL url = test_server_->GetURL("/CaptureRequest");
+  ASSERT_TRUE(test::LoadUrl(web_view, net::NSURLWithGURL(url)));
+
+  // Investigates the HTTP headers captured by CaptureRequestHandler(), and
+  // tests that they include User-Agent HTTP header with the specified product
+  // name. /echoheader?User-Agent provided by EmbeddedTestServer cannot be used
+  // here because it returns content with type text/plain, but we cannot extract
+  // the content using test::WaitForWebViewContainingTextOrTimeout() because
+  // JavaScript cannot be executed on text/plain content.
+  ASSERT_NE(nullptr, last_request_.get());
+  auto user_agent_it = last_request_->headers.find("User-Agent");
+  ASSERT_NE(last_request_->headers.end(), user_agent_it);
+  EXPECT_EQ("FooCustomUserAgent", user_agent_it->second);
+}
+
 // Tests +[CWVWebView setUserAgentProduct] and +[CWVWebView userAgentProduct].
 TEST_F(WebViewTest, UserAgentProduct) {
   ASSERT_TRUE(test_server_->Start());
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index f7b7285..3e7694ab 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -1449,43 +1449,48 @@
         final CameraCharacteristics cameraCharacteristics = getCameraCharacteristics(index);
         if (cameraCharacteristics == null) return null;
 
-        final int[] capabilities =
-                cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
-        // Per-format frame rate via getOutputMinFrameDuration() is only available if the
-        // property REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR is set.
-        boolean minFrameDurationAvailable = false;
-        for (int cap : capabilities) {
-            if (cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) {
-                minFrameDurationAvailable = true;
-                break;
-            }
-        }
-
-        ArrayList<VideoCaptureFormat> formatList = new ArrayList<VideoCaptureFormat>();
-        final StreamConfigurationMap streamMap =
-                cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-        final int[] formats = streamMap.getOutputFormats();
-        for (int format : formats) {
-            final Size[] sizes = streamMap.getOutputSizes(format);
-            if (sizes == null) continue;
-            for (Size size : sizes) {
-                double minFrameRate = 0.0f;
-                if (minFrameDurationAvailable) {
-                    final long minFrameDurationInNanoseconds =
-                            streamMap.getOutputMinFrameDuration(format, size);
-                    minFrameRate = (minFrameDurationInNanoseconds == 0)
-                            ? 0.0f
-                            : (kNanosecondsPerSecond / minFrameDurationInNanoseconds);
-                } else {
-                    // TODO(mcasas): find out where to get the info from in this case.
-                    // Hint: perhaps using SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS.
-                    minFrameRate = 0.0;
+        try {
+            final int[] capabilities =
+                    cameraCharacteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+            // Per-format frame rate via getOutputMinFrameDuration() is only available if the
+            // property REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR is set.
+            boolean minFrameDurationAvailable = false;
+            for (int cap : capabilities) {
+                if (cap == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) {
+                    minFrameDurationAvailable = true;
+                    break;
                 }
-                formatList.add(new VideoCaptureFormat(
-                        size.getWidth(), size.getHeight(), (int) minFrameRate, format));
             }
+
+            ArrayList<VideoCaptureFormat> formatList = new ArrayList<VideoCaptureFormat>();
+            final StreamConfigurationMap streamMap = cameraCharacteristics.get(
+                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+            final int[] formats = streamMap.getOutputFormats();
+            for (int format : formats) {
+                final Size[] sizes = streamMap.getOutputSizes(format);
+                if (sizes == null) continue;
+                for (Size size : sizes) {
+                    double minFrameRate = 0.0f;
+                    if (minFrameDurationAvailable) {
+                        final long minFrameDurationInNanoseconds =
+                                streamMap.getOutputMinFrameDuration(format, size);
+                        minFrameRate = (minFrameDurationInNanoseconds == 0)
+                                ? 0.0f
+                                : (kNanosecondsPerSecond / minFrameDurationInNanoseconds);
+                    } else {
+                        // TODO(mcasas): find out where to get the info from in this case.
+                        // Hint: perhaps using SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS.
+                        minFrameRate = 0.0;
+                    }
+                    formatList.add(new VideoCaptureFormat(
+                            size.getWidth(), size.getHeight(), (int) minFrameRate, format));
+                }
+            }
+            return formatList.toArray(new VideoCaptureFormat[formatList.size()]);
+        } catch (Exception e) {
+            Log.e(TAG, "Unable to catch device supported video formats: ", e);
+            return null;
         }
-        return formatList.toArray(new VideoCaptureFormat[formatList.size()]);
     }
 
     VideoCaptureCamera2(int index, long nativeVideoCaptureDeviceAndroid) {
diff --git a/media/filters/audio_renderer_algorithm.cc b/media/filters/audio_renderer_algorithm.cc
index a827544..bf4103b 100644
--- a/media/filters/audio_renderer_algorithm.cc
+++ b/media/filters/audio_renderer_algorithm.cc
@@ -415,6 +415,19 @@
          (resampler_ ? static_cast<int>(resampler_->BufferedFrames()) : 0);
 }
 
+double AudioRendererAlgorithm::DelayInFrames(double playback_rate) const {
+  int slower_step = std::ceil(ola_window_size_ * playback_rate);
+  int faster_step = std::ceil(ola_window_size_ / playback_rate);
+
+  // When |playback_rate| ~= 1, we read directly from |audio_buffer_|.
+  if (ola_window_size_ <= faster_step && slower_step >= ola_window_size_)
+    return audio_buffer_.frames();
+
+  const float buffered_output_frames = BufferedFrames() / playback_rate;
+  const float unconverted_output_frames = buffered_output_frames - output_time_;
+  return unconverted_output_frames + num_complete_frames_;
+}
+
 bool AudioRendererAlgorithm::CanPerformWsola() const {
   const int search_block_size = num_candidate_blocks_ + (ola_window_size_ - 1);
   const int frames = audio_buffer_.frames();
diff --git a/media/filters/audio_renderer_algorithm.h b/media/filters/audio_renderer_algorithm.h
index 700d9a06..4d9e7470 100644
--- a/media/filters/audio_renderer_algorithm.h
+++ b/media/filters/audio_renderer_algorithm.h
@@ -120,6 +120,14 @@
   // more data than |audio_buffer_| was intending to hold.
   int BufferedFrames() const;
 
+  // Returns the effective delay in output frames at the given |playback rate|.
+  // Effectively this tells the caller, if new audio is enqueued via
+  // EnqueueBuffer(), how many frames must be read via FillBuffer() at the
+  // |playback_rate| before the new audio is read out. Note that this is
+  // approximate, since due to WSOLA the audio output doesn't always directly
+  // correspond to the audio input (some samples may be duplicated or skipped).
+  double DelayInFrames(double playback_rate) const;
+
   // Returns the samples per second for this audio stream.
   int samples_per_second() const { return samples_per_second_; }
 
diff --git a/media/fuchsia/audio/fuchsia_audio_renderer.cc b/media/fuchsia/audio/fuchsia_audio_renderer.cc
index 28d34b224..871c566 100644
--- a/media/fuchsia/audio/fuchsia_audio_renderer.cc
+++ b/media/fuchsia/audio/fuchsia_audio_renderer.cc
@@ -470,7 +470,7 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (!demuxer_stream_ || read_timer_.IsRunning() || is_demuxer_read_pending_ ||
-      GetPlaybackState() == PlaybackState::kEndOfStream ||
+      is_at_end_of_stream_ ||
       num_pending_packets_ >= stream_sink_buffers_.size()) {
     return;
   }
@@ -535,10 +535,7 @@
   }
 
   if (buffer->end_of_stream()) {
-    {
-      base::AutoLock lock(timeline_lock_);
-      SetPlaybackState(PlaybackState::kEndOfStream);
-    }
+    is_at_end_of_stream_ = true;
     stream_sink_->EndOfStream();
 
     // No more data is going to be buffered. Update buffering state to ensure
@@ -618,13 +615,13 @@
 
 void FuchsiaAudioRenderer::FlushInternal() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(GetPlaybackState() == PlaybackState::kStopped ||
-         GetPlaybackState() == PlaybackState::kEndOfStream);
+  DCHECK(GetPlaybackState() == PlaybackState::kStopped || is_at_end_of_stream_);
 
   stream_sink_->DiscardAllPacketsNoReply();
   SetBufferState(BUFFERING_HAVE_NOTHING);
   last_packet_timestamp_ = base::TimeDelta::Min();
   read_timer_.Stop();
+  is_at_end_of_stream_ = false;
 
   if (is_demuxer_read_pending_) {
     drop_next_demuxer_read_result_ = true;
@@ -637,9 +634,7 @@
 }
 
 bool FuchsiaAudioRenderer::IsTimeMoving() {
-  return (state_ == PlaybackState::kPlaying ||
-          state_ == PlaybackState::kEndOfStream) &&
-         (media_delta_ > 0);
+  return state_ == PlaybackState::kPlaying && media_delta_ > 0;
 }
 
 void FuchsiaAudioRenderer::UpdateTimelineOnStop() {
diff --git a/media/fuchsia/audio/fuchsia_audio_renderer.h b/media/fuchsia/audio/fuchsia_audio_renderer.h
index 5269a5f6..65dd995 100644
--- a/media/fuchsia/audio/fuchsia_audio_renderer.h
+++ b/media/fuchsia/audio/fuchsia_audio_renderer.h
@@ -60,11 +60,9 @@
     // should not be used yet.
     kStarting,
 
+    // Playback is active. When the stream reaches EOS it stays in the kPlaying
+    // state.
     kPlaying,
-
-    // Received end-of-stream packet from the |demuxer_stream_|. Waiting for
-    // EndOfStream event from |audio_consumer_|.
-    kEndOfStream,
   };
 
   // Struct used to store state of an input buffer shared with the
@@ -170,6 +168,10 @@
   base::TimeDelta min_lead_time_;
   base::TimeDelta max_lead_time_;
 
+  // Set to true after we've received end-of-stream from the |demuxer_stream_|.
+  // The renderer may be restarted after Flush().
+  bool is_at_end_of_stream_ = false;
+
   // TimeSource interface is not single-threaded. The lock is used to guard
   // fields that are accessed in the TimeSource implementation. Note that these
   // fields are updated only on the main thread (which corresponds to the
diff --git a/media/fuchsia/camera/fake_fuchsia_camera.h b/media/fuchsia/camera/fake_fuchsia_camera.h
index 23a56e2..0fba3b2a 100644
--- a/media/fuchsia/camera/fake_fuchsia_camera.h
+++ b/media/fuchsia/camera/fake_fuchsia_camera.h
@@ -196,7 +196,7 @@
 
   const DevicesMap& devices() const { return devices_; }
 
-  // Removes camera device from the listd an returns corresponding
+  // Removes camera device from the list and returns the corresponding
   // FakeCameraStream and FakeCameraDevice. The caller may want to hold the
   // returned object, e.g. to ensure that the corresponding FIDL connections
   // are not dropped.
diff --git a/media/mojo/services/mojo_audio_decoder_service.cc b/media/mojo/services/mojo_audio_decoder_service.cc
index 589bce4..5a16ebc 100644
--- a/media/mojo/services/mojo_audio_decoder_service.cc
+++ b/media/mojo/services/mojo_audio_decoder_service.cc
@@ -110,8 +110,9 @@
 
   if (!status.is_ok()) {
     // Do not call decoder_->NeedsBitstreamConversion() if init failed.
-    std::move(callback).Run(std::move(status), false,
-                            AudioDecoderType::kUnknown);
+    std::move(callback).Run(
+        std::move(status), false,
+        decoder_ ? decoder_->GetDecoderType() : AudioDecoderType::kUnknown);
     return;
   }
 
diff --git a/media/mojo/services/mojo_video_decoder_service.cc b/media/mojo/services/mojo_video_decoder_service.cc
index 44ff3898..8bf12d16 100644
--- a/media/mojo/services/mojo_video_decoder_service.cc
+++ b/media/mojo/services/mojo_video_decoder_service.cc
@@ -310,7 +310,9 @@
                          status.code());
 
   if (!status.is_ok()) {
-    std::move(init_cb_).Run(status, false, 1, VideoDecoderType::kUnknown);
+    std::move(init_cb_).Run(
+        status, false, 1,
+        decoder_ ? decoder_->GetDecoderType() : VideoDecoderType::kUnknown);
     return;
   }
   std::move(init_cb_).Run(status, decoder_->NeedsBitstreamConversion(),
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index bc2c803..0f72c061 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -578,41 +578,38 @@
 
   bool QueryYUVA(const SkYUVAPixmapInfo::SupportedDataTypes&,
                  SkYUVAPixmapInfo* info) const override {
-    // Temporarily disabling this path to avoid creating YUV ImageData in
-    // GpuImageDecodeCache.
-    // TODO(crbug.com/921636): Restore the code below once YUV rendering support
-    // is added for VideoImageGenerator.
-    return false;
-#if 0
     SkYUVAInfo::PlaneConfig plane_config;
     SkYUVAInfo::Subsampling subsampling;
     std::tie(plane_config, subsampling) =
         VideoPixelFormatAsSkYUVAInfoValues(frame_->format());
-    if (plane_config == SkYUVAInfo::PlaneConfig::kUnknown) {
+    if (plane_config == SkYUVAInfo::PlaneConfig::kUnknown)
+      return false;
+
+    // Don't use the YUV conversion path for multi-plane RGB frames.
+    if (frame_->format() == PIXEL_FORMAT_I444 &&
+        frame_->ColorSpace().GetMatrixID() == gfx::ColorSpace::MatrixID::GBR) {
       return false;
     }
-    if (info) {
-      SkYUVColorSpace yuv_color_space;
-      if (!frame_->ColorSpace().ToSkYUVColorSpace(video_frame->BitDepth(),
-                                                  &yuv_color_space)) {
-        // TODO(hubbe): This really should default to rec709
-        // https://crbug.com/828599
-        yuv_color_space = kRec601_SkYUVColorSpace;
-      }
-      // We use the Y plane size because it may get rounded up to an even size.
-      // Our implementation of GetYUVAPlanes expects this.
-      gfx::Size y_size =
-          VideoFrame::PlaneSize(frame_->format(), VideoFrame::kYPlane,
-                                gfx::Size(frame_->visible_rect().width(),
-                                          frame_->visible_rect().height()));
-      SkYUVAInfo yuva_info =
-          SkYUVAInfo({y_size.width(), y_size.height()}, plane_config,
-                     subsampling, yuv_color_space);
-      *info = SkYUVAPixmapInfo(yuva_info, SkYUVAPixmapInfo::DataType::kUnorm8,
-                               /* row bytes */ nullptr);
+
+    if (!info)
+      return true;
+
+    SkYUVColorSpace yuv_color_space;
+    if (!frame_->ColorSpace().ToSkYUVColorSpace(frame_->BitDepth(),
+                                                &yuv_color_space)) {
+      // TODO(crbug.com/828599): This should default to BT.709 color space.
+      yuv_color_space = kRec601_SkYUVColorSpace;
     }
+
+    // We use the Y plane size because it may get rounded up to an even size.
+    // Our implementation of GetYUVAPlanes expects this.
+    auto y_size = VideoFrame::PlaneSize(frame_->format(), VideoFrame::kYPlane,
+                                        frame_->visible_rect().size());
+    auto yuva_info = SkYUVAInfo({y_size.width(), y_size.height()}, plane_config,
+                                subsampling, yuv_color_space);
+    *info = SkYUVAPixmapInfo(yuva_info, SkYUVAPixmapInfo::DataType::kUnorm8,
+                             /*rowBytes=*/nullptr);
     return true;
-#endif
   }
 
   bool GetYUVAPlanes(const SkYUVAPixmaps& pixmaps,
@@ -621,50 +618,32 @@
     DCHECK_EQ(frame_index, 0u);
     DCHECK_EQ(pixmaps.numPlanes(), 3);
 
-    if (DCHECK_IS_ON()) {
-      SkYUVAInfo::PlaneConfig plane_config;
-      SkYUVAInfo::Subsampling subsampling;
-      std::tie(plane_config, subsampling) =
-          VideoPixelFormatAsSkYUVAInfoValues(frame_->format());
-      DCHECK_EQ(plane_config, pixmaps.yuvaInfo().planeConfig());
-      DCHECK_EQ(subsampling, pixmaps.yuvaInfo().subsampling());
-    }
+#if DCHECK_IS_ON()
+    SkYUVAInfo::PlaneConfig plane_config;
+    SkYUVAInfo::Subsampling subsampling;
+    std::tie(plane_config, subsampling) =
+        VideoPixelFormatAsSkYUVAInfoValues(frame_->format());
+    DCHECK_EQ(plane_config, pixmaps.yuvaInfo().planeConfig());
+    DCHECK_EQ(subsampling, pixmaps.yuvaInfo().subsampling());
+#endif
 
     for (int plane = VideoFrame::kYPlane; plane <= VideoFrame::kVPlane;
          ++plane) {
-      const gfx::Size size =
-          VideoFrame::PlaneSize(frame_->format(), plane,
-                                gfx::Size(frame_->visible_rect().width(),
-                                          frame_->visible_rect().height()));
-      if (size.width() != pixmaps.plane(plane).width() ||
-          size.height() != pixmaps.plane(plane).height()) {
+      const auto plane_size = VideoFrame::PlaneSize(
+          frame_->format(), plane, frame_->visible_rect().size());
+      if (plane_size.width() != pixmaps.plane(plane).width() ||
+          plane_size.height() != pixmaps.plane(plane).height()) {
         return false;
       }
 
-      size_t offset;
-      const int y_shift =
-          (frame_->format() == media::PIXEL_FORMAT_I422) ? 0 : 1;
-      if (plane == VideoFrame::kYPlane) {
-        offset =
-            (frame_->stride(VideoFrame::kYPlane) * frame_->visible_rect().y()) +
-            frame_->visible_rect().x();
-      } else {
-        offset = (frame_->stride(VideoFrame::kUPlane) *
-                  (frame_->visible_rect().y() >> y_shift)) +
-                 (frame_->visible_rect().x() >> 1);
-      }
+      const auto& out_plane = pixmaps.plane(plane);
 
-      // Copy the frame to the supplied memory.
-      // TODO: Find a way (API change?) to avoid this copy.
-      uint8_t* out_line =
-          static_cast<uint8_t*>(pixmaps.plane(plane).writable_addr());
-      int out_line_stride = static_cast<int>(pixmaps.plane(plane).rowBytes());
-      uint8_t* in_line = frame_->data(plane) + offset;
-      int in_line_stride = frame_->stride(plane);
-      int plane_height = pixmaps.plane(plane).height();
-      int bytes_to_copy_per_line = std::min(out_line_stride, in_line_stride);
-      libyuv::CopyPlane(in_line, in_line_stride, out_line, out_line_stride,
-                        bytes_to_copy_per_line, plane_height);
+      // Copy the frame to the supplied memory. It'd be nice to avoid this copy,
+      // but the memory is externally owned so we can't w/o an API change.
+      libyuv::CopyPlane(frame_->visible_data(plane), frame_->stride(plane),
+                        reinterpret_cast<uint8_t*>(out_plane.writable_addr()),
+                        out_plane.rowBytes(), plane_size.width(),
+                        plane_size.height());
     }
     return true;
   }
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc
index 8d4adcc6..c1f7deb 100644
--- a/pdf/pdf_view_plugin_base.cc
+++ b/pdf/pdf_view_plugin_base.cc
@@ -406,7 +406,7 @@
   base::Value metadata(base::Value::Type::DICTIONARY);
   const DocumentMetadata& document_metadata = engine()->GetDocumentMetadata();
 
-  const std::u16string version = FormatPdfVersion(document_metadata.version);
+  const std::string version = FormatPdfVersion(document_metadata.version);
   if (!version.empty())
     metadata.SetStringKey("version", version);
 
diff --git a/pdf/ui/document_properties.cc b/pdf/ui/document_properties.cc
index 30f72fa..87f7f83a 100644
--- a/pdf/ui/document_properties.cc
+++ b/pdf/ui/document_properties.cc
@@ -6,10 +6,10 @@
 
 #include <string>
 
-#include "base/check_op.h"
 #include "base/i18n/number_formatting.h"
 #include "base/i18n/rtl.h"
 #include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #include "pdf/document_metadata.h"
 #include "printing/units.h"
@@ -91,45 +91,32 @@
       GetOrientation(size_points.value()));
 }
 
-std::u16string FormatPdfVersion(PdfVersion version) {
-  double value = 0;
+std::string FormatPdfVersion(PdfVersion version) {
   switch (version) {
     case PdfVersion::k1_0:
-      value = 1.0;
-      break;
+      return "1.0";
     case PdfVersion::k1_1:
-      value = 1.1;
-      break;
+      return "1.1";
     case PdfVersion::k1_2:
-      value = 1.2;
-      break;
+      return "1.2";
     case PdfVersion::k1_3:
-      value = 1.3;
-      break;
+      return "1.3";
     case PdfVersion::k1_4:
-      value = 1.4;
-      break;
+      return "1.4";
     case PdfVersion::k1_5:
-      value = 1.5;
-      break;
+      return "1.5";
     case PdfVersion::k1_6:
-      value = 1.6;
-      break;
+      return "1.6";
     case PdfVersion::k1_7:
-      value = 1.7;
-      break;
+      return "1.7";
     case PdfVersion::k2_0:
-      value = 2.0;
-      break;
+      return "2.0";
     case PdfVersion::kUnknown:
     case PdfVersion::k1_8:  // Not an actual version
-      return std::u16string();
+      return std::string();
   }
   // The default case is excluded from the above switch statement to ensure that
   // all supported versions are determinantly handled.
-
-  DCHECK_NE(0, value);
-  return base::FormatDouble(value, 1);
 }
 
 }  // namespace chrome_pdf
diff --git a/pdf/ui/document_properties.h b/pdf/ui/document_properties.h
index d3340a3..33bc176 100644
--- a/pdf/ui/document_properties.h
+++ b/pdf/ui/document_properties.h
@@ -26,8 +26,9 @@
 // Returns the string "Varies" if `size_points` is `base::nullopt`.
 std::u16string FormatPageSize(const base::Optional<gfx::Size>& size_points);
 
-// Formats `version` to a localized string suitable for display to a user.
-std::u16string FormatPdfVersion(PdfVersion version);
+// Formats `version` to a string suitable for display to a user. Version numbers
+// do not require localization.
+std::string FormatPdfVersion(PdfVersion version);
 
 }  // namespace chrome_pdf
 
diff --git a/pdf/ui/document_properties_unittest.cc b/pdf/ui/document_properties_unittest.cc
index 159aebd..173eff5 100644
--- a/pdf/ui/document_properties_unittest.cc
+++ b/pdf/ui/document_properties_unittest.cc
@@ -10,19 +10,21 @@
 #include "base/i18n/rtl.h"
 #include "base/optional.h"
 #include "components/strings/grit/components_strings.h"
+#include "pdf/document_metadata.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/resource/mock_resource_bundle_delegate.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/size.h"
 
-using ::testing::Invoke;
-using ::testing::NiceMock;
-
 namespace chrome_pdf {
 
 namespace {
 
+using ::testing::Invoke;
+using ::testing::IsEmpty;
+using ::testing::NiceMock;
+
 bool GetPageSizeString(int message_id, std::u16string* value) {
   switch (message_id) {
     case IDS_PDF_PROPERTIES_PAGE_SIZE_VALUE_INCH:
@@ -152,4 +154,14 @@
             u"1,000.00 × 1,000.00 in (portrait)");
 }
 
+TEST(FormatPdfVersion, Valid) {
+  EXPECT_EQ(FormatPdfVersion(PdfVersion::k1_7), "1.7");
+  EXPECT_EQ(FormatPdfVersion(PdfVersion::k2_0), "2.0");
+}
+
+TEST(FormatPdfVersion, Invalid) {
+  EXPECT_THAT(FormatPdfVersion(PdfVersion::kUnknown), IsEmpty());
+  EXPECT_THAT(FormatPdfVersion(PdfVersion::k1_8), IsEmpty());
+}
+
 }  // namespace chrome_pdf
diff --git a/services/device/generic_sensor/platform_sensor.cc b/services/device/generic_sensor/platform_sensor.cc
index 09f80f93..d0ccc94 100644
--- a/services/device/generic_sensor/platform_sensor.cc
+++ b/services/device/generic_sensor/platform_sensor.cc
@@ -7,8 +7,9 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/check.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "services/device/generic_sensor/platform_sensor_provider.h"
 #include "services/device/generic_sensor/platform_sensor_util.h"
 #include "services/device/public/cpp/generic_sensor/platform_sensor_configuration.h"
@@ -19,7 +20,7 @@
 PlatformSensor::PlatformSensor(mojom::SensorType type,
                                SensorReadingSharedBuffer* reading_buffer,
                                PlatformSensorProvider* provider)
-    : task_runner_(base::ThreadTaskRunnerHandle::Get()),
+    : main_task_runner_(base::SequencedTaskRunnerHandle::Get()),
       reading_buffer_(reading_buffer),
       type_(type),
       provider_(provider),
@@ -124,7 +125,7 @@
 void PlatformSensor::UpdateSharedBufferAndNotifyClients(
     const SensorReading& reading) {
   UpdateSharedBuffer(reading);
-  task_runner_->PostTask(
+  main_task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&PlatformSensor::NotifySensorReadingChanged,
                                 weak_factory_.GetWeakPtr()));
 }
@@ -200,4 +201,9 @@
   return config_map_;
 }
 
+void PlatformSensor::PostTaskToMainSequence(const base::Location& location,
+                                            base::OnceClosure task) {
+  main_task_runner()->PostTask(location, std::move(task));
+}
+
 }  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor.h b/services/device/generic_sensor/platform_sensor.h
index 932fae9..e60d016 100644
--- a/services/device/generic_sensor/platform_sensor.h
+++ b/services/device/generic_sensor/platform_sensor.h
@@ -9,11 +9,13 @@
 #include <map>
 #include <memory>
 
+#include "base/callback_forward.h"
+#include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "services/device/public/cpp/generic_sensor/sensor_reading.h"
@@ -80,6 +82,11 @@
   using ConfigMap = std::map<Client*, std::list<PlatformSensorConfiguration>>;
   const ConfigMap& GetConfigMapForTesting() const;
 
+  // Called by API users to post a task on |main_task_runner_| when run from a
+  // different sequence.
+  void PostTaskToMainSequence(const base::Location& location,
+                              base::OnceClosure task);
+
  protected:
   virtual ~PlatformSensor();
   PlatformSensor(mojom::SensorType type,
@@ -92,12 +99,14 @@
   virtual bool StartSensor(
       const PlatformSensorConfiguration& configuration) = 0;
   virtual void StopSensor() = 0;
-  // Updates shared buffer with new sensor reading data and schedules
-  // NotifySensorReadingChanged invocation on IPC thread.
+
+  // Updates the shared buffer with new sensor reading data and posts a task to
+  // invoke NotifySensorReadingChanged() on |main_task_runner_|.
   // Note: this method is thread-safe.
   void UpdateSharedBufferAndNotifyClients(const SensorReading& reading);
 
   // Updates shared buffer with provided SensorReading
+  // Note: this method is thread-safe.
   void UpdateSharedBuffer(const SensorReading& reading);
 
   void NotifySensorReadingChanged();
@@ -105,14 +114,20 @@
 
   void ResetReadingBuffer();
 
-  // Task runner that is used by mojo objects for the IPC.
-  // If platform sensor events are processed on a different
-  // thread, notifications are forwarded to |task_runner_|.
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  // Returns the task runner where this object has been created. Subclasses can
+  // use it to post tasks to the right sequence when running on a different task
+  // runner.
+  scoped_refptr<base::SequencedTaskRunner> main_task_runner() const {
+    return main_task_runner_;
+  }
+
   base::ObserverList<Client, true>::Unchecked clients_;
 
  private:
   friend class base::RefCountedThreadSafe<PlatformSensor>;
+
+  scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
+
   SensorReadingSharedBuffer* reading_buffer_;  // NOTE: Owned by |provider_|.
   mojom::SensorType type_;
   ConfigMap config_map_;
diff --git a/services/device/generic_sensor/platform_sensor_android.cc b/services/device/generic_sensor/platform_sensor_android.cc
index a1a2900..cd2b46f 100644
--- a/services/device/generic_sensor/platform_sensor_android.cc
+++ b/services/device/generic_sensor/platform_sensor_android.cc
@@ -70,7 +70,7 @@
 void PlatformSensorAndroid::NotifyPlatformSensorError(
     JNIEnv*,
     const JavaRef<jobject>& caller) {
-  task_runner_->PostTask(
+  PostTaskToMainSequence(
       FROM_HERE,
       base::BindOnce(&PlatformSensorAndroid::NotifySensorError, this));
 }
diff --git a/services/device/generic_sensor/platform_sensor_chromeos.cc b/services/device/generic_sensor/platform_sensor_chromeos.cc
index 660175a..1040eb05 100644
--- a/services/device/generic_sensor/platform_sensor_chromeos.cc
+++ b/services/device/generic_sensor/platform_sensor_chromeos.cc
@@ -260,7 +260,7 @@
 PlatformSensorChromeOS::BindNewPipeAndPassRemote() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!receiver_.is_bound());
-  auto pending_remote = receiver_.BindNewPipeAndPassRemote(task_runner_);
+  auto pending_remote = receiver_.BindNewPipeAndPassRemote(main_task_runner());
 
   receiver_.set_disconnect_handler(
       base::BindOnce(&PlatformSensorChromeOS::OnObserverDisconnect,
diff --git a/services/device/generic_sensor/platform_sensor_linux.cc b/services/device/generic_sensor/platform_sensor_linux.cc
index b5798bd..ff0d1ff 100644
--- a/services/device/generic_sensor/platform_sensor_linux.cc
+++ b/services/device/generic_sensor/platform_sensor_linux.cc
@@ -32,21 +32,21 @@
       default_configuration_(
           PlatformSensorConfiguration(sensor_device->device_frequency)),
       reporting_mode_(sensor_device->reporting_mode) {
-  sensor_reader_ = SensorReader::Create(
-      *sensor_device, weak_factory_.GetWeakPtr(), task_runner_);
+  sensor_reader_ =
+      SensorReader::Create(*sensor_device, weak_factory_.GetWeakPtr());
 }
 
 PlatformSensorLinux::~PlatformSensorLinux() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
 }
 
 mojom::ReportingMode PlatformSensorLinux::GetReportingMode() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   return reporting_mode_;
 }
 
 void PlatformSensorLinux::UpdatePlatformSensorReading(SensorReading reading) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   if (GetReportingMode() == mojom::ReportingMode::ON_CHANGE &&
       !HaveValuesChanged(reading, old_values_)) {
     return;
@@ -58,31 +58,31 @@
 }
 
 void PlatformSensorLinux::NotifyPlatformSensorError() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   NotifySensorError();
 }
 
 bool PlatformSensorLinux::StartSensor(
     const PlatformSensorConfiguration& configuration) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   sensor_reader_->StartFetchingData(configuration);
   return true;
 }
 
 void PlatformSensorLinux::StopSensor() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   sensor_reader_->StopFetchingData();
 }
 
 bool PlatformSensorLinux::CheckSensorConfiguration(
     const PlatformSensorConfiguration& configuration) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   return configuration.frequency() > 0 &&
          configuration.frequency() <= default_configuration_.frequency();
 }
 
 PlatformSensorConfiguration PlatformSensorLinux::GetDefaultConfiguration() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   return default_configuration_;
 }
 
diff --git a/services/device/generic_sensor/platform_sensor_reader_linux.cc b/services/device/generic_sensor/platform_sensor_reader_linux.cc
index d718da1..6ff992d 100644
--- a/services/device/generic_sensor/platform_sensor_reader_linux.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_linux.cc
@@ -10,7 +10,6 @@
 #include "base/files/file_util.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -26,8 +25,7 @@
 class PollingSensorReader : public SensorReader {
  public:
   PollingSensorReader(const SensorInfoLinux& sensor_info,
-                      base::WeakPtr<PlatformSensorLinux> sensor,
-                      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+                      base::WeakPtr<PlatformSensorLinux> sensor);
   ~PollingSensorReader() override;
 
   // SensorReader overrides
@@ -179,9 +177,8 @@
 
 PollingSensorReader::PollingSensorReader(
     const SensorInfoLinux& sensor_info,
-    base::WeakPtr<PlatformSensorLinux> sensor,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : SensorReader(sensor, std::move(task_runner)),
+    base::WeakPtr<PlatformSensorLinux> sensor)
+    : SensorReader(sensor),
       blocking_task_helper_(nullptr,
                             base::OnTaskRunnerDeleter(blocking_task_runner_)) {
   // We need to properly initialize |blocking_task_helper_| here because we need
@@ -218,10 +215,12 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!is_reading_active_)
     return;
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&PlatformSensorLinux::UpdatePlatformSensorReading, sensor_,
-                     reading));
+  if (sensor_) {
+    sensor_->PostTaskToMainSequence(
+        FROM_HERE,
+        base::BindOnce(&PlatformSensorLinux::UpdatePlatformSensorReading,
+                       sensor_, reading));
+  }
 }
 
 void PollingSensorReader::OnReadingError() {
@@ -232,27 +231,20 @@
 // static
 std::unique_ptr<SensorReader> SensorReader::Create(
     const SensorInfoLinux& sensor_info,
-    base::WeakPtr<PlatformSensorLinux> sensor,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    base::WeakPtr<PlatformSensorLinux> sensor) {
   // TODO(maksims): implement triggered reading. At the moment,
   // only polling read is supported.
-  return std::make_unique<PollingSensorReader>(sensor_info, sensor,
-                                               std::move(task_runner));
+  return std::make_unique<PollingSensorReader>(sensor_info, sensor);
 }
 
-SensorReader::SensorReader(
-    base::WeakPtr<PlatformSensorLinux> sensor,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : sensor_(sensor),
-      task_runner_(std::move(task_runner)),
-      is_reading_active_(false) {
-}
+SensorReader::SensorReader(base::WeakPtr<PlatformSensorLinux> sensor)
+    : sensor_(sensor), is_reading_active_(false) {}
 
 SensorReader::~SensorReader() = default;
 
 void SensorReader::NotifyReadError() {
-  if (is_reading_active_) {
-    task_runner_->PostTask(
+  if (is_reading_active_ && sensor_) {
+    sensor_->PostTaskToMainSequence(
         FROM_HERE,
         base::BindOnce(&PlatformSensorLinux::NotifyPlatformSensorError,
                        sensor_));
diff --git a/services/device/generic_sensor/platform_sensor_reader_linux.h b/services/device/generic_sensor/platform_sensor_reader_linux.h
index 1b88eca3..1f631616 100644
--- a/services/device/generic_sensor/platform_sensor_reader_linux.h
+++ b/services/device/generic_sensor/platform_sensor_reader_linux.h
@@ -9,10 +9,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace device {
 
 class PlatformSensorConfiguration;
@@ -28,8 +24,7 @@
   // reader is supported.
   static std::unique_ptr<SensorReader> Create(
       const SensorInfoLinux& sensor_info,
-      base::WeakPtr<PlatformSensorLinux> sensor,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+      base::WeakPtr<PlatformSensorLinux> sensor);
 
   virtual ~SensorReader();
 
@@ -42,8 +37,7 @@
   virtual void StopFetchingData() = 0;
 
  protected:
-  SensorReader(base::WeakPtr<PlatformSensorLinux> sensor,
-               scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  explicit SensorReader(base::WeakPtr<PlatformSensorLinux> sensor);
 
   // Notifies |sensor_| about an error.
   void NotifyReadError();
@@ -52,10 +46,6 @@
   // readings to.
   base::WeakPtr<PlatformSensorLinux> sensor_;
 
-  // A task runner that is used to report about new readings and errors
-  // to a |sensor_|.
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
   // Indicates if reading is active.
   bool is_reading_active_;
 
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.cc b/services/device/generic_sensor/platform_sensor_reader_win.cc
index 63bd89b..4543fe5 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -405,7 +405,7 @@
     Microsoft::WRL::ComPtr<ISensor> sensor,
     std::unique_ptr<ReaderInitParams> params)
     : init_params_(std::move(params)),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      com_sta_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       sensor_active_(false),
       client_(nullptr),
       sensor_(sensor),
@@ -430,7 +430,7 @@
 }
 
 PlatformSensorReaderWin32::~PlatformSensorReaderWin32() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(com_sta_task_runner_->BelongsToCurrentThread());
 }
 
 bool PlatformSensorReaderWin32::StartSensor(
@@ -441,7 +441,7 @@
     return false;
 
   if (!sensor_active_) {
-    task_runner_->PostTask(
+    com_sta_task_runner_->PostTask(
         FROM_HERE, base::BindOnce(&PlatformSensorReaderWin32::ListenSensorEvent,
                                   weak_factory_.GetWeakPtr()));
     sensor_active_ = true;
diff --git a/services/device/generic_sensor/platform_sensor_reader_win.h b/services/device/generic_sensor/platform_sensor_reader_win.h
index 40bc079f..3cc7ccc 100644
--- a/services/device/generic_sensor/platform_sensor_reader_win.h
+++ b/services/device/generic_sensor/platform_sensor_reader_win.h
@@ -59,7 +59,7 @@
   friend class EventListener;
 
   const std::unique_ptr<ReaderInitParams> init_params_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
   // Following class members are protected by lock, because SetClient,
   // StartSensor and StopSensor are called from another thread by
   // PlatformSensorWin that can modify internal state of the object.
diff --git a/services/device/generic_sensor/platform_sensor_win.cc b/services/device/generic_sensor/platform_sensor_win.cc
index 153a7b4..7a4559e 100644
--- a/services/device/generic_sensor/platform_sensor_win.cc
+++ b/services/device/generic_sensor/platform_sensor_win.cc
@@ -49,25 +49,25 @@
 }
 
 void PlatformSensorWin::OnSensorError() {
-  task_runner_->PostTask(FROM_HERE,
+  PostTaskToMainSequence(FROM_HERE,
                          base::BindOnce(&PlatformSensorWin::NotifySensorError,
                                         weak_factory_.GetWeakPtr()));
 }
 
 bool PlatformSensorWin::StartSensor(
     const PlatformSensorConfiguration& configuration) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   return sensor_reader_->StartSensor(configuration);
 }
 
 void PlatformSensorWin::StopSensor() {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   sensor_reader_->StopSensor();
 }
 
 bool PlatformSensorWin::CheckSensorConfiguration(
     const PlatformSensorConfiguration& configuration) {
-  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(main_task_runner()->RunsTasksInCurrentSequence());
   base::TimeDelta minimal_reporting_interval_ms =
       sensor_reader_->GetMinimalReportingInterval();
   if (minimal_reporting_interval_ms.is_zero())
diff --git a/services/tracing/public/cpp/perfetto/posix_system_producer.cc b/services/tracing/public/cpp/perfetto/posix_system_producer.cc
index edb0ed3..3a4e943 100644
--- a/services/tracing/public/cpp/perfetto/posix_system_producer.cc
+++ b/services/tracing/public/cpp/perfetto/posix_system_producer.cc
@@ -29,7 +29,7 @@
 #endif  // defined(OS_ANDROID)
 
 #if !defined(OS_ANDROID)
-#include "mojo/public/cpp/bindings/shared_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/tracing/public/cpp/system_tracing_service.h"
 #endif
 
@@ -425,9 +425,8 @@
 
 #if !defined(OS_ANDROID)
   // If the child process hasn't received the Mojo remote, try again later.
-  auto shared_remote =
-      TracedProcessImpl::GetInstance()->system_tracing_service();
-  if (!shared_remote.is_bound()) {
+  auto& remote = TracedProcessImpl::GetInstance()->system_tracing_service();
+  if (!remote.is_bound()) {
     DelayedReconnect();
     return;
   }
@@ -456,7 +455,7 @@
       std::move(producer_name), weak_ptr_factory_.GetWeakPtr());
 
   // Open the socket remotely using Mojo.
-  shared_remote->OpenProducerSocket(std::move(callback));
+  remote->OpenProducerSocket(std::move(callback));
 #endif  // !defined(OS_ANDROID)
 }
 
diff --git a/services/tracing/public/cpp/traced_process_impl.cc b/services/tracing/public/cpp/traced_process_impl.cc
index 5cc6bca..5dcac3d 100644
--- a/services/tracing/public/cpp/traced_process_impl.cc
+++ b/services/tracing/public/cpp/traced_process_impl.cc
@@ -57,8 +57,28 @@
   receiver_.Bind(std::move(receiver));
 }
 
+mojo::Remote<mojom::SystemTracingService>&
+TracedProcessImpl::system_tracing_service() {
+  // |system_tracing_service_| can only be used on the Perfetto task runner.
+  auto task_runner =
+      PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner();
+  DCHECK(task_runner && task_runner->RunsTasksInCurrentSequence());
+  return system_tracing_service_;
+}
+
 void TracedProcessImpl::EnableSystemTracingService(
     mojo::PendingRemote<mojom::SystemTracingService> remote) {
+  auto task_runner =
+      PerfettoTracedProcess::GetTaskRunner()->GetOrCreateTaskRunner();
+  if (!task_runner->RunsTasksInCurrentSequence()) {
+    // |system_tracing_service_| is bound on the Perfetto task runner.
+    task_runner->PostTask(
+        FROM_HERE,
+        base::BindOnce(&TracedProcessImpl::EnableSystemTracingService,
+                       base::Unretained(this), std::move(remote)));
+    return;
+  }
+
   system_tracing_service_.Bind(std::move(remote), nullptr);
 }
 
diff --git a/services/tracing/public/cpp/traced_process_impl.h b/services/tracing/public/cpp/traced_process_impl.h
index 74e4f02..7618141 100644
--- a/services/tracing/public/cpp/traced_process_impl.h
+++ b/services/tracing/public/cpp/traced_process_impl.h
@@ -12,7 +12,6 @@
 #include "base/no_destructor.h"
 #include "base/sequence_checker.h"
 #include "mojo/public/cpp/bindings/remote.h"
-#include "mojo/public/cpp/bindings/shared_remote.h"
 #include "services/tracing/public/mojom/system_tracing_service.mojom.h"
 #include "services/tracing/public/mojom/traced_process.mojom.h"
 
@@ -44,9 +43,7 @@
   // Populate categories from all of the registered agents.
   void GetCategories(std::set<std::string>* category_set);
 
-  mojo::SharedRemote<mojom::SystemTracingService> system_tracing_service() {
-    return system_tracing_service_;
-  }
+  mojo::Remote<mojom::SystemTracingService>& system_tracing_service();
 
  private:
   friend class base::NoDestructor<TracedProcessImpl>;
@@ -60,7 +57,7 @@
 
   std::set<BaseAgent*> agents_;
   mojo::Receiver<tracing::mojom::TracedProcess> receiver_{this};
-  mojo::SharedRemote<mojom::SystemTracingService> system_tracing_service_;
+  mojo::Remote<mojom::SystemTracingService> system_tracing_service_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index ff20b1cd..49493ad8 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -6650,6 +6650,7 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
+              "cpu": "x86-64",
               "os": "Ubuntu-16.04",
               "pool": "chrome.tests"
             }
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index ae0701c..38807cc6 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -3803,7 +3803,8 @@
         "args": [
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices",
-          "--avd-config=../../tools/android/avd/proto/generic_android30.textpb"
+          "--avd-config=../../tools/android/avd/proto/generic_android30.textpb",
+          "--gtest_filter=-org.chromium.weblayer.test.MediaCaptureTest.*"
         ],
         "merge": {
           "args": [
@@ -4320,11 +4321,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -4334,7 +4335,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4399,11 +4400,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -4413,7 +4414,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4557,11 +4558,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -4571,7 +4572,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4636,11 +4637,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -4650,7 +4651,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4862,11 +4863,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -4876,7 +4877,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4941,11 +4942,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -4955,7 +4956,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5099,11 +5100,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -5113,7 +5114,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5178,11 +5179,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -5192,7 +5193,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 2638ed97..09109d21 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46668,11 +46668,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -46682,7 +46682,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46747,11 +46747,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -46761,7 +46761,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46905,11 +46905,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -46919,7 +46919,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46984,11 +46984,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -46998,7 +46998,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47209,11 +47209,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -47223,7 +47223,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47288,11 +47288,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -47302,7 +47302,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47446,11 +47446,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.96",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 89.0.4389.97",
         "resultdb": {
           "enable": true
         },
@@ -47460,7 +47460,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M89",
-              "revision": "version:89.0.4389.96"
+              "revision": "version:89.0.4389.97"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47525,11 +47525,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.30",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.31",
         "resultdb": {
           "enable": true
         },
@@ -47539,7 +47539,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.30"
+              "revision": "version:90.0.4430.31"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 452eb97..ef95214 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -7384,7 +7384,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7422,7 +7423,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7460,7 +7462,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7498,7 +7501,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7540,7 +7544,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7582,6 +7587,7 @@
           "--no-xvfb",
           "--use-weston",
           "--weston-use-gl",
+          "--weston-debug-logging",
           "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
@@ -7629,6 +7635,7 @@
           "--no-xvfb",
           "--use-weston",
           "--weston-use-gl",
+          "--weston-debug-logging",
           "--git-revision=${got_revision}"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
@@ -7673,7 +7680,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7711,7 +7719,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
@@ -7750,7 +7759,8 @@
           "--xvfb",
           "--no-xvfb",
           "--use-weston",
-          "--weston-use-gl"
+          "--weston-use-gl",
+          "--weston-debug-logging"
         ],
         "isolate_name": "telemetry_gpu_integration_test",
         "merge": {
diff --git a/testing/buildbot/chromium.swangle.json b/testing/buildbot/chromium.swangle.json
index 16eaf34..cf66667 100644
--- a/testing/buildbot/chromium.swangle.json
+++ b/testing/buildbot/chromium.swangle.json
@@ -503,432 +503,6 @@
       }
     ]
   },
-  "linux-swangle-tot-angle-x86": {
-    "gtest_tests": [
-      {
-        "args": [
-          "angle_deqp_egl_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_egl_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_egl_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test": "angle_deqp_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "angle_deqp_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_end2end_tests",
-          "--bot-mode",
-          "--gtest_filter=*Vulkan_SwiftShader*",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_end2end_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_end2end_tests/",
-        "use_isolated_scripts_api": true
-      }
-    ]
-  },
   "linux-swangle-tot-swiftshader-x64": {
     "gtest_tests": [
       {
@@ -1355,432 +929,6 @@
       }
     ]
   },
-  "linux-swangle-tot-swiftshader-x86": {
-    "gtest_tests": [
-      {
-        "args": [
-          "angle_deqp_egl_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_egl_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_egl_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test": "angle_deqp_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "angle_deqp_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_end2end_tests",
-          "--bot-mode",
-          "--gtest_filter=*Vulkan_SwiftShader*",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_end2end_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_end2end_tests/",
-        "use_isolated_scripts_api": true
-      }
-    ]
-  },
   "linux-swangle-x64": {
     "gtest_tests": [
       {
@@ -2207,432 +1355,6 @@
       }
     ]
   },
-  "linux-swangle-x86": {
-    "gtest_tests": [
-      {
-        "args": [
-          "angle_deqp_egl_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_egl_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_egl_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles31_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 10
-        },
-        "test": "angle_deqp_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate180_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate180_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate180_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate270_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate270_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate270_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_rotate90_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles3_rotate90_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_rotate90_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test": "angle_deqp_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles2_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles2_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles31_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles31_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles31_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_deqp_khr_gles3_tests",
-          "--use-angle=swiftshader",
-          "--bot-mode",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_khr_gles3_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_deqp_khr_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "angle_end2end_tests",
-          "--bot-mode",
-          "--gtest_filter=*Vulkan_SwiftShader*",
-          "--xvfb"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "gpu": "none",
-              "os": "Ubuntu-16.04",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "hard_timeout": 900,
-          "io_timeout": 900,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_end2end_tests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:angle_end2end_tests/",
-        "use_isolated_scripts_api": true
-      }
-    ]
-  },
   "mac-swangle-chromium-x64": {
     "isolated_scripts": [
       {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index c0d999d..a2da3bc 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -223,13 +223,6 @@
   ]
 }
 
-source_set("webview_cts_tests_filters") {
-  testonly = true
-
-  data =
-      [ "//testing/buildbot/filters/mojo.fyi.network_webview_CTS_test.filter" ]
-}
-
 source_set("webview_instrumentation_test_apk_filters") {
   testonly = true
 
diff --git a/testing/buildbot/filters/mojo.fyi.network_webview_CTS_test.filter b/testing/buildbot/filters/mojo.fyi.network_webview_CTS_test.filter
deleted file mode 100644
index f8717ea..0000000
--- a/testing/buildbot/filters/mojo.fyi.network_webview_CTS_test.filter
+++ /dev/null
@@ -1,13 +0,0 @@
-# These CTS tests currently fail when run with --enable-features=NetworkService,NetworkServiceInProcess
-#
-# Note: webview aims to support running network service in-process, so the
-# tests are also running with NS IP. Multiprocess webview currently does not
-# support running NS OOP, https://crbug.com/882650
-#
-# Note: the CTS test runner (run_cts.py) will implicitly skip "expected
-# failures" (tests which are flaky or failing for the non-Network Service path
-# too). These tests are listed in
-# android_webview/tools/cts_config/webview_cts_gcs_path.json &
-# android_webview/tools/cts_config/expected_failure_on_bot.json.
-
-# Tests that fail with NetworkService feature enabled. https://crbug.com/923938
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index a688cba..eb378473 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -950,6 +950,7 @@
         'swarming': {
           'dimension_sets': [
             {
+              'cpu': 'x86-64',
               'os': 'Ubuntu-16.04',
             },
           ],
@@ -3041,6 +3042,16 @@
       }
     }
   },
+  'weblayer_private_instrumentation_test_apk': {
+    'modifications': {
+      # TODO(crbug.com/1189403): Remove the filter once the issue is fixed.
+      'android-11-x86-fyi-rel': {
+        'args': [
+          '--gtest_filter=-org.chromium.weblayer.test.MediaCaptureTest.*',
+        ],
+      },
+    },
+  },
   'weblayer_shell_wpt': {
     'modifications': {
       # TODO(crbug.com/1171555): remove this when test can run with more emulators
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 2ea2a4e..e2b229c 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -2650,6 +2650,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -2665,6 +2666,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3034,6 +3036,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'args': [
           '--extra-browser-args=--use-cmd-decoder=passthrough --use-gl=angle',
@@ -3052,6 +3055,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3068,6 +3072,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3083,6 +3088,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3110,6 +3116,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'chrome-gpu-gold-service-account',
@@ -3138,6 +3145,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'chrome-gpu-gold-service-account',
@@ -3166,6 +3174,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3403,6 +3412,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'args': [
           '--extra-browser-args=--use-cmd-decoder=validating',
@@ -3421,6 +3431,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3437,6 +3448,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3452,6 +3464,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3479,6 +3492,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'chrome-gpu-gold-service-account',
@@ -3507,6 +3521,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'chrome-gpu-gold-service-account',
@@ -3535,6 +3550,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3594,6 +3610,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3673,6 +3690,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3761,6 +3779,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'mixins': [
           'enable_resultdb',
@@ -3899,6 +3918,7 @@
           '--no-xvfb',
           '--use-weston',
           '--weston-use-gl',
+          '--weston-debug-logging',
         ],
         'args': [
           # On dual-GPU devices we want the high-performance GPU to be active
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index f75e898..773bbfe 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -311,13 +311,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.30',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.31',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.30',
+          'revision': 'version:90.0.4430.31',
         }
       ],
     },
@@ -335,13 +335,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=89',
     ],
-    'identifier': 'Implementation Library Skew Tests For 89.0.4389.96',
+    'identifier': 'Implementation Library Skew Tests For 89.0.4389.97',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.96',
+          'revision': 'version:89.0.4389.97',
         }
       ],
     },
@@ -383,13 +383,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.30',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.31',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.30',
+          'revision': 'version:90.0.4430.31',
         }
       ],
     },
@@ -407,13 +407,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=89',
     ],
-    'identifier': 'Implementation Library Skew Tests For 89.0.4389.96',
+    'identifier': 'Implementation Library Skew Tests For 89.0.4389.97',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.96',
+          'revision': 'version:89.0.4389.97',
         }
       ],
     },
@@ -455,13 +455,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=90',
     ],
-    'identifier': 'Client Library Skew Tests For 90.0.4430.30',
+    'identifier': 'Client Library Skew Tests For 90.0.4430.31',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.30',
+          'revision': 'version:90.0.4430.31',
         }
       ],
     },
@@ -479,13 +479,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=89',
     ],
-    'identifier': 'Client Library Skew Tests For 89.0.4389.96',
+    'identifier': 'Client Library Skew Tests For 89.0.4389.97',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M89',
-          'revision': 'version:89.0.4389.96',
+          'revision': 'version:89.0.4389.97',
         }
       ],
     },
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index eff17dc..ea4876815 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5473,20 +5473,6 @@
           'gtest_tests': 'swangle_gtests',
         },
       },
-      'linux-swangle-tot-angle-x86' : {
-        'os_type': 'linux',
-        'mixins': [
-          'gpu-swarming-pool',
-          'isolate_profile_data',
-          'linux-xenial',
-          'no_gpu',
-          'timeout_15m',
-          'x86-64',
-        ],
-        'test_suites': {
-          'gtest_tests': 'swangle_gtests',
-        },
-      },
       'linux-swangle-tot-swiftshader-x64' : {
         'os_type': 'linux',
         'mixins': [
@@ -5501,20 +5487,6 @@
           'gtest_tests': 'swangle_gtests',
         },
       },
-      'linux-swangle-tot-swiftshader-x86' : {
-        'os_type': 'linux',
-        'mixins': [
-          'gpu-swarming-pool',
-          'isolate_profile_data',
-          'linux-xenial',
-          'no_gpu',
-          'timeout_15m',
-          'x86-64',
-        ],
-        'test_suites': {
-          'gtest_tests': 'swangle_gtests',
-        },
-      },
       'linux-swangle-x64' : {
         'os_type': 'linux',
         'mixins': [
@@ -5529,20 +5501,6 @@
           'gtest_tests': 'swangle_gtests',
         },
       },
-      'linux-swangle-x86' : {
-        'os_type': 'linux',
-        'mixins': [
-          'gpu-swarming-pool',
-          'isolate_profile_data',
-          'linux-xenial',
-          'no_gpu',
-          'timeout_15m',
-          'x86-64',
-        ],
-        'test_suites': {
-          'gtest_tests': 'swangle_gtests',
-        },
-      },
       'mac-swangle-chromium-x64' : {
         'os_type': 'mac',
         'browser_config': 'release',
diff --git a/testing/scripts/run_android_wpt.py b/testing/scripts/run_android_wpt.py
index b6f2fcb..99815b95 100755
--- a/testing/scripts/run_android_wpt.py
+++ b/testing/scripts/run_android_wpt.py
@@ -119,6 +119,9 @@
     # Here we add all of the arguments required to run WPT tests on Android.
     rest_args.extend([self.options.wpt_path])
 
+    # TODO(crbug.com/1166741): We should be running WPT under Python 3.
+    rest_args.extend(["--py2"])
+
     # vpython has packages needed by wpt, so force it to skip the setup
     rest_args.extend(["--venv=../../", "--skip-venv-setup"])
 
diff --git a/testing/scripts/run_wpt_tests.py b/testing/scripts/run_wpt_tests.py
index c762579..88ce325 100755
--- a/testing/scripts/run_wpt_tests.py
+++ b/testing/scripts/run_wpt_tests.py
@@ -73,6 +73,8 @@
             WPT_BINARY,
             "--venv=" + SRC_DIR,
             "--skip-venv-setup",
+            # TODO(crbug.com/1166741): We should be running WPT under Python 3.
+            "--py3",
             "run",
             "chrome"
         ] + self.options.test_list + [
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index a3e960e..2ec7cef 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2045,21 +2045,6 @@
             ]
         }
     ],
-    "CrostiniWebUIUpgrader": [
-        {
-            "platforms": [
-                "chromeos"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "CrostiniWebUIUpgrader"
-                    ]
-                }
-            ]
-        }
-    ],
     "CupsIppPrintingBackend": [
         {
             "platforms": [
diff --git a/testing/xvfb.py b/testing/xvfb.py
index c03568a..1ba992a 100755
--- a/testing/xvfb.py
+++ b/testing/xvfb.py
@@ -8,6 +8,7 @@
 
 from __future__ import print_function
 
+import copy
 import os
 import os.path
 import psutil
@@ -285,6 +286,11 @@
       weston_cmd.append('--use-gl')
       cmd.remove('--weston-use-gl')
 
+    if '--weston-debug-logging' in cmd:
+      cmd.remove('--weston-debug-logging')
+      env = copy.deepcopy(env)
+      env['WAYLAND_DEBUG'] = '1'
+
     weston_proc_display = None
     for _ in range(10):
       weston_proc = subprocess.Popen(
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 3ec282b4..e3f7268 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -6745,11 +6745,11 @@
   # Returns metrics relating to the layouting of the page, such as viewport bounds/scale.
   command getLayoutMetrics
     returns
-      # Deprecated metrics relating to the layout viewport. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `normalisedLayoutViewport` instead.
+      # Deprecated metrics relating to the layout viewport. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `cssLayoutViewport` instead.
       deprecated LayoutViewport layoutViewport
-      # Deprecated metrics relating to the visual viewport. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `normalisedVisualViewport` instead.
+      # Deprecated metrics relating to the visual viewport. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `cssVisualViewport` instead.
       deprecated VisualViewport visualViewport
-      # Deprecated size of scrollable area. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `normalisedContentSize` instead.
+      # Deprecated size of scrollable area. Can be in DP or in CSS pixels depending on the `enable-use-zoom-for-dsf` flag. Use `cssContentSize` instead.
       deprecated DOM.Rect contentSize
       # Metrics relating to the layout viewport in CSS pixels.
       LayoutViewport cssLayoutViewport
diff --git a/third_party/blink/renderer/bindings/generated_in_modules.gni b/third_party/blink/renderer/bindings/generated_in_modules.gni
index fdd762e..61e2c82 100644
--- a/third_party/blink/renderer/bindings/generated_in_modules.gni
+++ b/third_party/blink/renderer/bindings/generated_in_modules.gni
@@ -279,6 +279,8 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_init.h",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_metadata.cc",
+  "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_metadata.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk_metadata.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/modules/v8/v8_event_source_init.cc",
diff --git a/third_party/blink/renderer/bindings/idl_in_modules.gni b/third_party/blink/renderer/bindings/idl_in_modules.gni
index 8d9d4c1..b0286cb 100644
--- a/third_party/blink/renderer/bindings/idl_in_modules.gni
+++ b/third_party/blink/renderer/bindings/idl_in_modules.gni
@@ -784,6 +784,7 @@
           "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_init.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_init.idl",
+          "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_metadata.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_metadata.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl",
           "//third_party/blink/renderer/modules/webcodecs/encoded_video_chunk_output_callback.idl",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index bd6c8b5d..f4fbb8b 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1382,6 +1382,7 @@
     "layout/multi_column_fragmentainer_group_test.cc",
     "layout/ng/custom/layout_worklet_test.cc",
     "layout/ng/exclusions/ng_exclusion_space_test.cc",
+    "layout/ng/flex/ng_flex_layout_algorithm_test.cc",
     "layout/ng/geometry/ng_box_strut_test.cc",
     "layout/ng/geometry/ng_static_position_test.cc",
     "layout/ng/grid/ng_grid_child_iterator_test.cc",
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index a1533c7..c0a05842 100644
--- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -1315,20 +1315,22 @@
 
 void CollectQuadsRecursive(Node* node, Vector<FloatQuad>& out_quads) {
   LayoutObject* layout_object = node->GetLayoutObject();
-  if (!layout_object)
-    return;
-
   // For inline elements, absoluteQuads will return a line box based on the
   // line-height and font metrics, which is technically incorrect as replaced
   // elements like images should use their intristic height and expand the
   // linebox  as needed. To get an appropriate quads we descend
   // into the children and have them add their boxes.
-  if (layout_object->IsLayoutInline() &&
+  //
+  // Elements with display:contents style (such as slots) do not have layout
+  // objects and we always look at their contents.
+  if (((layout_object && layout_object->IsLayoutInline()) ||
+       (!layout_object && node->IsElementNode() &&
+        To<Element>(node)->HasDisplayContentsStyle())) &&
       LayoutTreeBuilderTraversal::FirstChild(*node)) {
     for (Node* child = LayoutTreeBuilderTraversal::FirstChild(*node); child;
          child = LayoutTreeBuilderTraversal::NextSibling(*child))
       CollectQuadsRecursive(child, out_quads);
-  } else {
+  } else if (layout_object) {
     layout_object->AbsoluteQuads(out_quads);
   }
 }
@@ -1577,6 +1579,8 @@
       show_extension_lines_(highlight_config.show_extension_lines),
       show_accessibility_info_(highlight_config.show_accessibility_info),
       color_format_(highlight_config.color_format) {
+  DCHECK(node->GetDocument().Lifecycle().GetState() >=
+         DocumentLifecycle::kLayoutClean);
   AppendPathsForShapeOutside(node, highlight_config);
   AppendNodeHighlight(node, highlight_config);
   auto* text_node = DynamicTo<Text>(node);
diff --git a/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.cc b/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.cc
index e951543e..e49da87 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
@@ -78,6 +79,46 @@
   return LayoutNGMixin<LayoutBlock>::IsChildAllowed(object, style);
 }
 
+// This is devtools' entry point into layout. This function is intended to have
+// no side effects on the NGFragment tree or the LayoutObject tree.
+//
+// Execution time of this function is not critical, but the flex item layouts
+// will hit their caches, so it's probably fast anyway.
+DevtoolsFlexInfo LayoutNGFlexibleBox::LayoutForDevtools() {
+  DCHECK(!NeedsLayout());
+  DevtoolsReadonlyLayoutScope fragments_and_tree_are_now_readonly;
+  const NGLayoutResult* old_layout_result = GetCachedLayoutResult();
+#if DCHECK_IS_ON()
+  MinMaxSizes old_min_max_sizes = IntrinsicLogicalWidths();
+  String old_string = old_layout_result->PhysicalFragment().DumpFragmentTree(
+      NGPhysicalLineBoxFragment::DumpAll);
+#endif
+
+  DCHECK(old_layout_result);
+  const NGConstraintSpace& constraint_space =
+      old_layout_result->GetConstraintSpaceForCaching();
+
+  NGBlockNode node(this);
+  NGFragmentGeometry fragment_geometry =
+      CalculateInitialFragmentGeometry(constraint_space, node);
+  NGLayoutAlgorithmParams params(node, fragment_geometry, constraint_space);
+  DevtoolsFlexInfo flex_info;
+  NGFlexLayoutAlgorithm flex_algorithm(params, &flex_info);
+  auto new_result = flex_algorithm.Layout();
+
+#if DCHECK_IS_ON()
+  MinMaxSizes new_min_max_sizes = IntrinsicLogicalWidths();
+  DCHECK_EQ(old_min_max_sizes, new_min_max_sizes)
+      << "Legacy min_max_sizes changed!";
+
+  String new_string = new_result->PhysicalFragment().DumpFragmentTree(
+      NGPhysicalLineBoxFragment::DumpAll);
+  DCHECK_EQ(old_string, new_string) << "Fragment tree changed!";
+#endif
+
+  return flex_info;
+}
+
 void LayoutNGFlexibleBox::RemoveChild(LayoutObject* child) {
   if (!DocumentBeingDestroyed() &&
       !StyleRef().IsDeprecatedFlexboxUsingFlexLayout())
diff --git a/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h b/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h
index 033479fa..9354338f 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h
@@ -11,6 +11,18 @@
 
 namespace blink {
 
+// Devtools uses this info to highlight lines and items on its flexbox overlay.
+// Devtools usually reads such info from the layout or fragment trees. But
+// Layout doesn't store this flex line -> flex items hierarchy there, or
+// anywhere, because neither paint nor ancestor layout needs it. So the NG flex
+// layout algorithm will fill one of these in when devtools requests it.
+struct DevtoolsFlexInfo {
+  struct Line {
+    Vector<PhysicalRect> items;
+  };
+  Vector<Line> lines;
+};
+
 class CORE_EXPORT LayoutNGFlexibleBox : public LayoutNGMixin<LayoutBlock> {
  public:
   explicit LayoutNGFlexibleBox(Element*);
@@ -24,6 +36,8 @@
   bool IsFlexibleBoxIncludingNG() const final { return true; }
   const char* GetName() const override { return "LayoutNGFlexibleBox"; }
 
+  DevtoolsFlexInfo LayoutForDevtools();
+
  protected:
   bool IsChildAllowed(LayoutObject* object,
                       const ComputedStyle& style) const override;
@@ -35,6 +49,13 @@
   }
 };
 
+template <>
+struct DowncastTraits<LayoutNGFlexibleBox> {
+  static bool AllowFrom(const LayoutObject& object) {
+    return object.IsFlexibleBoxIncludingNG() && object.IsLayoutNGObject();
+  }
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_FLEX_LAYOUT_NG_FLEXIBLE_BOX_H_
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
index 16835f0..905a94b2 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_button.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
+#include "third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/ng/flex/ng_flex_child_iterator.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
@@ -32,7 +33,8 @@
 namespace blink {
 
 NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(
-    const NGLayoutAlgorithmParams& params)
+    const NGLayoutAlgorithmParams& params,
+    DevtoolsFlexInfo* layout_info_for_devtools)
     : NGLayoutAlgorithm(params),
       is_column_(Style().ResolvedIsColumnFlexDirection()),
       is_horizontal_flow_(FlexLayoutAlgorithm::IsHorizontalFlow(Style())),
@@ -44,7 +46,8 @@
       algorithm_(&Style(),
                  MainAxisContentExtent(LayoutUnit::Max()),
                  child_percentage_size_,
-                 &Node().GetDocument()) {}
+                 &Node().GetDocument()),
+      layout_info_for_devtools_(layout_info_for_devtools) {}
 
 bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(
     const NGBlockNode& child) const {
@@ -930,6 +933,8 @@
 scoped_refptr<const NGLayoutResult>
 NGFlexLayoutAlgorithm::RelayoutIgnoringChildScrollbarChanges() {
   DCHECK(!ignore_child_scrollbar_changes_);
+  DCHECK(!layout_info_for_devtools_);
+  DCHECK(!DevtoolsReadonlyLayoutScope::InDevtoolsLayout());
   NGLayoutAlgorithmParams params(
       Node(), container_builder_.InitialFragmentGeometry(), ConstraintSpace(),
       BreakToken(), /* early_break */ nullptr);
@@ -1190,6 +1195,8 @@
   bool success = true;
   LayoutUnit overflow_block_size;
   for (FlexLine& line_context : line_contexts) {
+    if (UNLIKELY(layout_info_for_devtools_))
+      layout_info_for_devtools_->lines.push_back(DevtoolsFlexInfo::Line());
     for (wtf_size_t child_number = 0;
          child_number < line_context.line_items_.size(); ++child_number) {
       FlexItem& flex_item = line_context.line_items_[child_number];
@@ -1218,6 +1225,22 @@
 
       container_builder_.AddChild(physical_fragment,
                                   {location.X(), location.Y()});
+      if (UNLIKELY(layout_info_for_devtools_)) {
+        // If this is a "devtools layout", execution speed isn't critical but we
+        // have to not adversely affect execution speed of a regular layout.
+        PhysicalRect item_rect;
+        item_rect.size = physical_fragment.Size();
+        PhysicalSize flexbox_size = ToPhysicalSize(
+            container_builder_.Size(), ConstraintSpace().GetWritingMode());
+        item_rect.offset =
+            LogicalOffset(location.X(), location.Y())
+                .ConvertToPhysical(ConstraintSpace().GetWritingDirection(),
+                                   flexbox_size, item_rect.size);
+        // devtools uses margin box.
+        item_rect.Expand(flex_item.physical_margins_);
+        DCHECK_GE(layout_info_for_devtools_->lines.size(), 1u);
+        layout_info_for_devtools_->lines.back().items.push_back(item_rect);
+      }
 
       flex_item.ng_input_node_.StoreMargins(flex_item.physical_margins_);
 
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
index 4fb29772..a48b53d 100644
--- a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h
@@ -15,13 +15,15 @@
 class NGBlockNode;
 class NGBlockBreakToken;
 class NGBoxFragment;
+struct DevtoolsFlexInfo;
 
 class CORE_EXPORT NGFlexLayoutAlgorithm
     : public NGLayoutAlgorithm<NGBlockNode,
                                NGBoxFragmentBuilder,
                                NGBlockBreakToken> {
  public:
-  NGFlexLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+  explicit NGFlexLayoutAlgorithm(const NGLayoutAlgorithmParams& params,
+                                 DevtoolsFlexInfo* devtools = nullptr);
 
   MinMaxSizesResult ComputeMinMaxSizes(const MinMaxSizesInput&) const override;
   scoped_refptr<const NGLayoutResult> Layout() override;
@@ -86,6 +88,7 @@
 
   bool ignore_child_scrollbar_changes_ = false;
   FlexLayoutAlgorithm algorithm_;
+  DevtoolsFlexInfo* layout_info_for_devtools_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm_test.cc
new file mode 100644
index 0000000..53c4655
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm_test.cc
@@ -0,0 +1,103 @@
+// 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 "third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+namespace {
+
+class NGFlexLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
+ protected:
+  DevtoolsFlexInfo LayoutForDevtools(const String& body_content) {
+    SetBodyInnerHTML(body_content);
+    UpdateAllLifecyclePhasesForTest();
+    LayoutNGFlexibleBox* flex =
+        To<LayoutNGFlexibleBox>(GetLayoutObjectByElementId("flexbox"));
+    EXPECT_NE(flex, nullptr);
+    return flex->LayoutForDevtools();
+  }
+};
+
+TEST_F(NGFlexLayoutAlgorithmTest, DetailsFlexDoesntCrash) {
+  SetBodyInnerHTML(R"HTML(
+    <details style="display:flex"></details>
+  )HTML");
+  UpdateAllLifecyclePhasesForTest();
+  // No crash is good.
+}
+
+TEST_F(NGFlexLayoutAlgorithmTest, DevtoolsBasic) {
+  DevtoolsFlexInfo devtools = LayoutForDevtools(R"HTML(
+    <div style="display:flex; width: 100px;" id=flexbox>
+      <div style="flex-grow: 1; height: 50px;"></div>
+      <div style="flex-grow: 1"></div>
+    </div>
+  )HTML");
+  EXPECT_EQ(devtools.lines.size(), 1u);
+  EXPECT_EQ(devtools.lines[0].items.size(), 2u);
+  EXPECT_EQ(devtools.lines[0].items[0], PhysicalRect(0, 0, 50, 50));
+  EXPECT_EQ(devtools.lines[0].items[0], PhysicalRect(0, 0, 50, 50));
+}
+
+TEST_F(NGFlexLayoutAlgorithmTest, DevtoolsWrap) {
+  DevtoolsFlexInfo devtools = LayoutForDevtools(R"HTML(
+    <div style="display:flex; width: 100px; flex-wrap: wrap;" id=flexbox>
+      <div style="min-width: 100px; height: 50px;"></div>
+      <div style="flex: 1 0 20px; height: 90px;"></div>
+    </div>
+  )HTML");
+  EXPECT_EQ(devtools.lines.size(), 2u);
+  EXPECT_EQ(devtools.lines[0].items.size(), 1u);
+  EXPECT_EQ(devtools.lines[0].items[0], PhysicalRect(0, 0, 100, 50));
+  EXPECT_EQ(devtools.lines[1].items.size(), 1u);
+  EXPECT_EQ(devtools.lines[1].items[0], PhysicalRect(0, 50, 100, 90));
+}
+
+TEST_F(NGFlexLayoutAlgorithmTest, DevtoolsCoordinates) {
+  DevtoolsFlexInfo devtools = LayoutForDevtools(R"HTML(
+    <div style="display:flex; width: 100px; flex-wrap: wrap; border-top: 2px solid; padding-top: 3px; border-left: 3px solid; padding-left: 5px; margin-left: 19px;" id=flexbox>
+      <div style="margin-left: 5px; min-width: 95px; height: 50px;"></div>
+      <div style="flex: 1 0 20px; height: 90px;"></div>
+    </div>
+  )HTML");
+  EXPECT_EQ(devtools.lines.size(), 2u);
+  EXPECT_EQ(devtools.lines[0].items.size(), 1u);
+  EXPECT_EQ(devtools.lines[0].items[0], PhysicalRect(8, 5, 100, 50));
+  EXPECT_EQ(devtools.lines[1].items.size(), 1u);
+  EXPECT_EQ(devtools.lines[1].items[0], PhysicalRect(8, 55, 100, 90));
+}
+
+TEST_F(NGFlexLayoutAlgorithmTest, DevtoolsOverflow) {
+  DevtoolsFlexInfo devtools = LayoutForDevtools(R"HTML(
+    <div style="display:flex; width: 100px; border-left: 1px solid; border-right: 3px solid;" id=flexbox>
+      <div style="min-width: 150px; height: 75px;"></div>
+    </div>
+  )HTML");
+  EXPECT_EQ(devtools.lines[0].items[0], PhysicalRect(1, 0, 150, 75));
+}
+
+TEST_F(NGFlexLayoutAlgorithmTest, DevtoolsWithRelPosItem) {
+  // Devtools' heuristic algorithm shows two lines for this case, but layout
+  // knows there's only one line.
+  DevtoolsFlexInfo devtools = LayoutForDevtools(R"HTML(
+  <style>
+  .item {
+    flex: 0 0 50px;
+    height: 50px;
+  }
+  </style>
+  <div style="display: flex;" id=flexbox>
+    <div class=item></div>
+    <div class=item style="position: relative; top: 60px; left: -10px"></div>
+  </div>
+  )HTML");
+  EXPECT_EQ(devtools.lines.size(), 1u);
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index dd6ec139..2d8a37e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -2496,16 +2496,6 @@
   EXPECT_EQ(*after->LastBaseline(), LayoutUnit(400));
 }
 
-// TODO(dgrogan): Move this to ng_flex_layout_algorithm_test.cc if there ever is
-// one.
-TEST_F(NGBlockLayoutAlgorithmTest, DetailsFlexDoesntCrash) {
-  SetBodyInnerHTML(R"HTML(
-    <details style="display:flex"></details>
-  )HTML");
-  UpdateAllLifecyclePhasesForTest();
-  // No crash is good.
-}
-
 TEST_F(NGBlockLayoutAlgorithmTest, LayoutRubyTextCrash) {
   // crbug.com/1102186. This test passes if no DCHECK failure.
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 5690440c..f93f8ccb 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -419,6 +419,11 @@
   scoped_refptr<const NGLayoutResult> layout_result =
       box_->CachedLayoutResult(constraint_space, break_token, early_break,
                                &fragment_geometry, &cache_status);
+  if (UNLIKELY(DevtoolsReadonlyLayoutScope::InDevtoolsLayout())) {
+    DCHECK_EQ(cache_status, NGLayoutCacheStatus::kHit);
+    DCHECK(!box_->NeedsLayoutOverflowRecalc());
+    return layout_result;
+  }
   if (cache_status == NGLayoutCacheStatus::kHit) {
     DCHECK(layout_result);
 
@@ -1628,6 +1633,14 @@
   scoped_refptr<const NGLayoutResult> layout_result =
       box_->GetCachedLayoutResult();
 
+  if (UNLIKELY(DevtoolsReadonlyLayoutScope::InDevtoolsLayout())) {
+    DCHECK(layout_result);
+    DCHECK(!box_->NeedsLayout());
+    DCHECK(!box_->NeedsLayoutOverflowRecalc());
+    DCHECK(MaySkipLegacyLayout(*this, *layout_result, constraint_space));
+    return layout_result;
+  }
+
   // We need to force a layout on the child if the constraint space given will
   // change the layout.
   bool needs_force_relayout =
@@ -1851,4 +1864,19 @@
       ->ReplaceLayoutResult(std::move(result), old_fragment);
 }
 
+static bool g_devtools_layout = false;
+bool DevtoolsReadonlyLayoutScope::InDevtoolsLayout() {
+  return g_devtools_layout;
+}
+
+DevtoolsReadonlyLayoutScope::DevtoolsReadonlyLayoutScope() {
+  DCHECK(!g_devtools_layout);
+  g_devtools_layout = true;
+}
+
+DevtoolsReadonlyLayoutScope::~DevtoolsReadonlyLayoutScope() {
+  DCHECK(g_devtools_layout);
+  g_devtools_layout = false;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index 1b33306..78dc8406 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -256,6 +256,19 @@
   }
 };
 
+// Devtools can trigger layout to collect devtools-specific data. We don't want
+// or need such devtools layouts to write to the fragment or layout trees. This
+// class sets a flag that is checked before storing the layout results. If the
+// flag is true, we bail before writing anything.
+class DevtoolsReadonlyLayoutScope {
+  STACK_ALLOCATED();
+
+ public:
+  DevtoolsReadonlyLayoutScope();
+  static bool InDevtoolsLayout();
+  ~DevtoolsReadonlyLayoutScope();
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BLOCK_NODE_H_
diff --git a/third_party/blink/renderer/modules/mediastream/BUILD.gn b/third_party/blink/renderer/modules/mediastream/BUILD.gn
index 5c8427a..ded9dc8f 100644
--- a/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -11,6 +11,8 @@
     "apply_constraints_request.cc",
     "apply_constraints_request.h",
     "dom_window_media_stream.h",
+    "frame_queue_underlying_source.cc",
+    "frame_queue_underlying_source.h",
     "identifiability_metrics.cc",
     "identifiability_metrics.h",
     "input_device_info.cc",
diff --git a/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.cc
new file mode 100644
index 0000000..58b9e54
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.cc
@@ -0,0 +1,186 @@
+// 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 "third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h"
+
+#include "media/base/video_frame.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
+#include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
+#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
+#include "third_party/blink/renderer/platform/bindings/exception_code.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#include "third_party/webrtc/api/frame_transformer_interface.h"
+
+namespace blink {
+
+template <typename NativeFrameType>
+FrameQueueUnderlyingSource<NativeFrameType>::FrameQueueUnderlyingSource(
+    ScriptState* script_state,
+    wtf_size_t max_queue_size)
+    : UnderlyingSourceBase(script_state),
+      realm_task_runner_(ExecutionContext::From(script_state)
+                             ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
+      max_queue_size_(std::max(1u, max_queue_size)) {}
+
+template <typename NativeFrameType>
+ScriptPromise FrameQueueUnderlyingSource<NativeFrameType>::pull(
+    ScriptState* script_state) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  if (!queue_.empty()) {
+    ProcessPullRequest();
+  } else {
+    is_pending_pull_ = true;
+  }
+
+  DCHECK_LT(queue_.size(), max_queue_size_);
+  return ScriptPromise::CastUndefined(script_state);
+}
+
+template <typename NativeFrameType>
+ScriptPromise FrameQueueUnderlyingSource<NativeFrameType>::Start(
+    ScriptState* script_state) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  if (!StartFrameDelivery()) {
+    // There is only one way in which this can fail for now. Perhaps
+    // implementations should return their own failure messages.
+    return ScriptPromise::RejectWithDOMException(
+        script_state,
+        DOMException::Create(
+            "Invalid track",
+            DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError)));
+  }
+
+  return ScriptPromise::CastUndefined(script_state);
+}
+
+template <typename NativeFrameType>
+ScriptPromise FrameQueueUnderlyingSource<NativeFrameType>::Cancel(
+    ScriptState* script_state,
+    ScriptValue reason) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  Close();
+  return ScriptPromise::CastUndefined(script_state);
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::Close() {
+  StopFrameDelivery();
+
+  if (Controller())
+    Controller()->Close();
+  queue_.clear();
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::Trace(
+    Visitor* visitor) const {
+  UnderlyingSourceBase::Trace(visitor);
+}
+
+template <typename NativeFrameType>
+double FrameQueueUnderlyingSource<NativeFrameType>::DesiredSizeForTesting()
+    const {
+  return Controller()->DesiredSize();
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::ContextDestroyed() {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  UnderlyingSourceBase::ContextDestroyed();
+  queue_.clear();
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::QueueFrame(
+    NativeFrameType media_frame) {
+  if (realm_task_runner_->RunsTasksInCurrentSequence()) {
+    QueueFrameOnRealmTaskRunner(std::move(media_frame));
+    return;
+  }
+
+  PostCrossThreadTask(
+      *realm_task_runner_, FROM_HERE,
+      CrossThreadBindOnce(&FrameQueueUnderlyingSource<
+                              NativeFrameType>::QueueFrameOnRealmTaskRunner,
+                          WrapCrossThreadPersistent(this),
+                          std::move(media_frame)));
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::QueueFrameOnRealmTaskRunner(
+    NativeFrameType media_frame) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK_LE(queue_.size(), max_queue_size_);
+
+  // The queue was stopped, and we shouldn't save frames.
+  if (!Controller())
+    return;
+
+  // If the |queue_| is empty and the consumer has signaled a pull, bypass
+  // |queue_| and send the frame directly to the stream controller.
+  if (queue_.empty() && is_pending_pull_) {
+    SendFrameToStream(std::move(media_frame));
+    return;
+  }
+
+  if (queue_.size() == max_queue_size_)
+    queue_.pop_front();
+
+  queue_.push_back(std::move(media_frame));
+  if (is_pending_pull_) {
+    ProcessPullRequest();
+  }
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::ProcessPullRequest() {
+  DCHECK(!queue_.empty());
+  SendFrameToStream(std::move(queue_.front()));
+  queue_.pop_front();
+}
+
+template <typename NativeFrameType>
+void FrameQueueUnderlyingSource<NativeFrameType>::SendFrameToStream(
+    NativeFrameType media_frame) {
+  DCHECK(Controller());
+  DCHECK(media_frame);
+
+  Controller()->Enqueue(MakeBlinkFrame(std::move(media_frame)));
+  is_pending_pull_ = false;
+}
+
+template <>
+ScriptWrappable*
+FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>::MakeBlinkFrame(
+    scoped_refptr<media::VideoFrame> media_frame) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
+      std::move(media_frame), GetExecutionContext());
+
+  if (stream_was_transferred_)
+    video_frame->handle()->SetCloseOnClone();
+
+  return video_frame;
+}
+
+template <>
+ScriptWrappable*
+FrameQueueUnderlyingSource<std::unique_ptr<AudioFrameSerializationData>>::
+    MakeBlinkFrame(std::unique_ptr<AudioFrameSerializationData> media_frame) {
+  DCHECK(realm_task_runner_->RunsTasksInCurrentSequence());
+  return MakeGarbageCollected<AudioFrame>(std::move(media_frame));
+}
+
+template class MODULES_TEMPLATE_EXPORT
+    FrameQueueUnderlyingSource<std::unique_ptr<AudioFrameSerializationData>>;
+template class MODULES_TEMPLATE_EXPORT
+    FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>;
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h b/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h
new file mode 100644
index 0000000..2ef60964
--- /dev/null
+++ b/third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h
@@ -0,0 +1,108 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_FRAME_QUEUE_UNDERLYING_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_FRAME_QUEUE_UNDERLYING_SOURCE_H_
+
+#include "base/threading/thread_checker.h"
+#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/deque.h"
+
+namespace blink {
+
+class AudioFrameSerializationData;
+
+template <typename NativeFrameType>
+class FrameQueueUnderlyingSource : public UnderlyingSourceBase {
+ public:
+  FrameQueueUnderlyingSource(ScriptState*, wtf_size_t queue_size);
+  ~FrameQueueUnderlyingSource() override = default;
+
+  FrameQueueUnderlyingSource(const FrameQueueUnderlyingSource&) = delete;
+  FrameQueueUnderlyingSource& operator=(const FrameQueueUnderlyingSource&) =
+      delete;
+
+  // UnderlyingSourceBase
+  ScriptPromise pull(ScriptState*) override;
+  ScriptPromise Start(ScriptState*) override;
+  ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
+
+  // ExecutionLifecycleObserver
+  void ContextDestroyed() override;
+
+  wtf_size_t MaxQueueSize() const { return max_queue_size_; }
+
+  // Clears all internal state and closes the UnderlyingSource's Controller.
+  // Must be called on |realm_task_runner_|.
+  void Close();
+
+  // Adds a frame to |queue_|, dropping the oldest frame if it is full.
+  // Can be called from any task runner, and will jump to |realm_task_runner_|.
+  void QueueFrame(NativeFrameType media_frame);
+
+  // Start or stop the delivery of frames via QueueFrame().
+  // Must be called on |main_trask_runner_|.
+  virtual bool StartFrameDelivery() = 0;
+  virtual void StopFrameDelivery() = 0;
+
+  // Temporary workaround for crbug.com/1182497. Marks blink::VideoFrames to be
+  // closed when cloned(), to prevent stalls when posting internally to a
+  // transferred stream.
+  void SetStreamWasTransferred() { stream_was_transferred_ = true; }
+
+  bool IsPendingPullForTesting() const { return is_pending_pull_; }
+  const Deque<NativeFrameType>& QueueForTesting() const { return queue_; }
+  double DesiredSizeForTesting() const;
+
+  void Trace(Visitor*) const override;
+
+ protected:
+  scoped_refptr<base::SequencedTaskRunner> GetSourceRunner() {
+    return realm_task_runner_;
+  }
+
+ private:
+  void QueueFrameOnRealmTaskRunner(NativeFrameType media_frame);
+  void ProcessPullRequest();
+  void SendFrameToStream(NativeFrameType media_frame);
+  ScriptWrappable* MakeBlinkFrame(NativeFrameType media_frame);
+
+  // Used when a stream endpoint was transferred to another realm, to
+  // automatically close frames as they are posted to the other stream.
+  bool stream_was_transferred_ = false;
+
+  // Main task runner for the window or worker context.
+  const scoped_refptr<base::SequencedTaskRunner> realm_task_runner_;
+
+  // An internal deque prior to the stream controller's queue. It acts as a ring
+  // buffer and allows dropping old frames instead of new ones in case frames
+  // accumulate due to slow consumption.
+  Deque<NativeFrameType> queue_;
+  const wtf_size_t max_queue_size_;
+  bool is_pending_pull_ = false;
+};
+
+template <>
+ScriptWrappable* FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>::
+    MakeBlinkFrame(scoped_refptr<media::VideoFrame>);
+
+template <>
+ScriptWrappable*
+    FrameQueueUnderlyingSource<std::unique_ptr<AudioFrameSerializationData>>::
+        MakeBlinkFrame(std::unique_ptr<AudioFrameSerializationData>);
+
+extern template class MODULES_EXTERN_TEMPLATE_EXPORT
+    FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>;
+extern template class MODULES_EXTERN_TEMPLATE_EXPORT
+    FrameQueueUnderlyingSource<std::unique_ptr<AudioFrameSerializationData>>;
+
+using VideoFrameQueueUnderlyingSource =
+    FrameQueueUnderlyingSource<scoped_refptr<media::VideoFrame>>;
+using AudioFrameQueueUnderlyingSource =
+    FrameQueueUnderlyingSource<std::unique_ptr<AudioFrameSerializationData>>;
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_FRAME_QUEUE_UNDERLYING_SOURCE_H_
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc
index 653aed5..fa9ee3a 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.cc
@@ -4,18 +4,9 @@
 
 #include "third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/webcodecs/audio_frame_serialization_data.h"
-#include "third_party/blink/renderer/platform/bindings/exception_code.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
-#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
-#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
-#include "third_party/webrtc/api/frame_transformer_interface.h"
 
 namespace blink {
 
@@ -23,52 +14,23 @@
     ScriptState* script_state,
     MediaStreamComponent* track,
     wtf_size_t max_queue_size)
-    : UnderlyingSourceBase(script_state),
-      main_task_runner_(ExecutionContext::From(script_state)
-                            ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
-      track_(track),
-      max_queue_size_(std::max(1u, max_queue_size)) {
+    : AudioFrameQueueUnderlyingSource(script_state, max_queue_size),
+      track_(track) {
   DCHECK(track_);
 }
 
-ScriptPromise MediaStreamAudioTrackUnderlyingSource::pull(
-    ScriptState* script_state) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  if (!queue_.empty()) {
-    ProcessPullRequest();
-  } else {
-    is_pending_pull_ = true;
-  }
-
-  DCHECK_LT(queue_.size(), max_queue_size_);
-  return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise MediaStreamAudioTrackUnderlyingSource::Start(
-    ScriptState* script_state) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+bool MediaStreamAudioTrackUnderlyingSource::StartFrameDelivery() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   MediaStreamAudioTrack* audio_track = MediaStreamAudioTrack::From(track_);
-  if (!audio_track) {
-    return ScriptPromise::RejectWithDOMException(
-        script_state,
-        DOMException::Create(
-            "No input track",
-            DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError)));
-  }
+  if (!audio_track)
+    return false;
+
   WebMediaStreamAudioSink::AddToAudioTrack(this, WebMediaStreamTrack(track_));
-
-  return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise MediaStreamAudioTrackUnderlyingSource::Cancel(
-    ScriptState* script_state,
-    ScriptValue reason) {
-  DisconnectFromTrack();
-  return ScriptPromise::CastUndefined(script_state);
+  return true;
 }
 
 void MediaStreamAudioTrackUnderlyingSource::DisconnectFromTrack() {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (!track_)
     return;
 
@@ -79,28 +41,9 @@
 }
 
 void MediaStreamAudioTrackUnderlyingSource::Trace(Visitor* visitor) const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   visitor->Trace(track_);
-  UnderlyingSourceBase::Trace(visitor);
-}
-
-double MediaStreamAudioTrackUnderlyingSource::DesiredSizeForTesting() const {
-  return Controller()->DesiredSize();
-}
-
-void MediaStreamAudioTrackUnderlyingSource::ContextDestroyed() {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  UnderlyingSourceBase::ContextDestroyed();
-  queue_.clear();
-}
-
-void MediaStreamAudioTrackUnderlyingSource::Close() {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  DisconnectFromTrack();
-
-  // Check for Controller(), as the context might have been destroyed.
-  if (Controller())
-    Controller()->Close();
-  queue_.clear();
+  AudioFrameQueueUnderlyingSource::Trace(visitor);
 }
 
 void MediaStreamAudioTrackUnderlyingSource::OnData(
@@ -116,32 +59,12 @@
       std::move(data_copy), audio_parameters_.sample_rate(),
       estimated_capture_time - base::TimeTicks());
 
-  PostCrossThreadTask(
-      *main_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(
-          &MediaStreamAudioTrackUnderlyingSource::OnDataOnMainThread,
-          WrapCrossThreadPersistent(this), std::move(queue_data)));
+  QueueFrame(std::move(queue_data));
 }
 
-void MediaStreamAudioTrackUnderlyingSource::OnDataOnMainThread(
-    std::unique_ptr<AudioFrameSerializationData> queue_data) {
-  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
-  DCHECK_LE(queue_.size(), max_queue_size_);
-
-  // If the |queue_| is empty and the consumer has signaled a pull, bypass
-  // |queue_| and send the frame directly to the stream controller.
-  if (queue_.empty() && is_pending_pull_) {
-    SendFrameToStream(std::move(queue_data));
-    return;
-  }
-
-  if (queue_.size() == max_queue_size_)
-    queue_.pop_front();
-
-  queue_.emplace_back(std::move(queue_data));
-  if (is_pending_pull_) {
-    ProcessPullRequest();
-  }
+void MediaStreamAudioTrackUnderlyingSource::StopFrameDelivery() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DisconnectFromTrack();
 }
 
 void MediaStreamAudioTrackUnderlyingSource::OnSetFormat(
@@ -150,21 +73,4 @@
   audio_parameters_ = params;
 }
 
-void MediaStreamAudioTrackUnderlyingSource::ProcessPullRequest() {
-  DCHECK(!queue_.empty());
-  SendFrameToStream(std::move(queue_.front()));
-  queue_.pop_front();
-}
-
-void MediaStreamAudioTrackUnderlyingSource::SendFrameToStream(
-    std::unique_ptr<AudioFrameSerializationData> queue_data) {
-  if (!Controller())
-    return;
-
-  AudioFrame* audio_frame =
-      MakeGarbageCollected<AudioFrame>(std::move(queue_data));
-  Controller()->Enqueue(audio_frame);
-  is_pending_pull_ = false;
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h b/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h
index 77e9c862..042be843 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_audio_track_underlying_source.h
@@ -5,13 +5,11 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_AUDIO_TRACK_UNDERLYING_SOURCE_H_
 
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
 #include "media/base/audio_parameters.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
-#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/webcodecs/audio_frame.h"
-#include "third_party/blink/renderer/platform/wtf/deque.h"
 
 namespace blink {
 
@@ -19,7 +17,7 @@
 class MediaStreamComponent;
 
 class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource
-    : public UnderlyingSourceBase,
+    : public AudioFrameQueueUnderlyingSource,
       public WebMediaStreamAudioSink {
  public:
   explicit MediaStreamAudioTrackUnderlyingSource(ScriptState*,
@@ -30,52 +28,28 @@
   MediaStreamAudioTrackUnderlyingSource& operator=(
       const MediaStreamAudioTrackUnderlyingSource&) = delete;
 
-  // UnderlyingSourceBase
-  ScriptPromise pull(ScriptState*) override;
-  ScriptPromise Start(ScriptState*) override;
-  ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
-
   // WebMediaStreamAudioSink
   void OnData(const media::AudioBus& audio_bus,
               base::TimeTicks estimated_capture_time) override;
   void OnSetFormat(const media::AudioParameters& params) override;
 
-  // ExecutionLifecycleObserver
-  void ContextDestroyed() override;
-
   MediaStreamComponent* Track() const { return track_.Get(); }
-  wtf_size_t MaxQueueSize() const { return max_queue_size_; }
 
-  const Deque<std::unique_ptr<AudioFrameSerializationData>>& QueueForTesting()
-      const {
-    return queue_;
-  }
-  bool IsPendingPullForTesting() const { return is_pending_pull_; }
-
-  double DesiredSizeForTesting() const;
-
-  void Close();
   void Trace(Visitor*) const override;
-
  private:
-  void ProcessPullRequest();
-  void SendFrameToStream(std::unique_ptr<AudioFrameSerializationData>);
+  // FrameQueueUnderlyingSource implementation.
+  bool StartFrameDelivery() override;
+  void StopFrameDelivery() override;
 
   void DisconnectFromTrack();
 
   void OnDataOnMainThread(std::unique_ptr<AudioFrameSerializationData> data);
 
-  const scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
   Member<MediaStreamComponent> track_;
 
   media::AudioParameters audio_parameters_;
 
-  // An internal deque prior to the stream controller's queue. It acts as a ring
-  // buffer and allows dropping old frames instead of new ones in case frames
-  // accumulate due to slow consumption.
-  Deque<std::unique_ptr<AudioFrameSerializationData>> queue_;
-  const wtf_size_t max_queue_size_;
-  bool is_pending_pull_ = false;
+  SEQUENCE_CHECKER(sequence_checker_);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc b/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
index 1902419..d39b82e 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_track_processor.cc
@@ -142,7 +142,8 @@
       MakeGarbageCollected<MediaStreamVideoTrackUnderlyingSource>(
           script_state, input_track_->Component(), buffer_size_);
   source_stream_ = ReadableStream::CreateWithCountQueueingStrategy(
-      script_state, video_underlying_source_, /*high_water_mark=*/0,
+      script_state, video_underlying_source_,
+      /*high_water_mark=*/0,
       video_underlying_source_->GetStreamTransferOptimizer());
 
   source_closer_ = MakeGarbageCollected<UnderlyingSourceCloser>(
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
index 0124062b..04e73e7 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_sink_test.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame.h"
 #include "third_party/blink/renderer/core/streams/writable_stream.h"
 #include "third_party/blink/renderer/core/streams/writable_stream_default_writer.h"
+#include "third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/renderer/modules/mediastream/mock_media_stream_video_sink.h"
 #include "third_party/blink/renderer/modules/mediastream/pushable_media_stream_video_source.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
index 5c76dc6..9a15f24 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.cc
@@ -4,19 +4,13 @@
 
 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/v8_throw_dom_exception.h"
-#include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/streams/readable_stream_default_controller_with_script_scope.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_track.h"
 #include "third_party/blink/renderer/modules/mediastream/media_stream_video_track.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/platform/bindings/exception_code.h"
-#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 #include "third_party/webrtc/api/frame_transformer_interface.h"
-
 namespace blink {
 
 // Temporary workaround for crbug.com/1182497.
@@ -31,7 +25,7 @@
 
  public:
   StreamTransferNotifier(
-      scoped_refptr<base::SingleThreadTaskRunner> original_runner,
+      scoped_refptr<base::SequencedTaskRunner> original_runner,
       OptimizerCallback callback)
       : original_runner_(std::move(original_runner)),
         callback_(std::move(callback)) {}
@@ -47,7 +41,7 @@
   }
 
  private:
-  scoped_refptr<base::SingleThreadTaskRunner> original_runner_;
+  scoped_refptr<base::SequencedTaskRunner> original_runner_;
   OptimizerCallback callback_;
 };
 
@@ -55,86 +49,26 @@
     ScriptState* script_state,
     MediaStreamComponent* track,
     wtf_size_t max_queue_size)
-    : UnderlyingSourceBase(script_state),
-      main_task_runner_(ExecutionContext::From(script_state)
-                            ->GetTaskRunner(TaskType::kInternalMediaRealTime)),
-      track_(track),
-      max_queue_size_(std::max(1u, max_queue_size)) {
+    : FrameQueueUnderlyingSource(script_state, max_queue_size), track_(track) {
   DCHECK(track_);
 }
 
-ScriptPromise MediaStreamVideoTrackUnderlyingSource::pull(
-    ScriptState* script_state) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  if (!queue_.empty()) {
-    ProcessPullRequest();
-  } else {
-    is_pending_pull_ = true;
-  }
-
-  DCHECK_LT(queue_.size(), max_queue_size_);
-  return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise MediaStreamVideoTrackUnderlyingSource::Start(
-    ScriptState* script_state) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  MediaStreamVideoTrack* video_track = MediaStreamVideoTrack::From(track_);
-  if (!video_track) {
-    return ScriptPromise::RejectWithDOMException(
-        script_state,
-        DOMException::Create(
-            "No input track",
-            DOMException::GetErrorName(DOMExceptionCode::kInvalidStateError)));
-  }
-  ConnectToTrack(WebMediaStreamTrack(track_),
-                 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
-                     &MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrack,
-                     WrapCrossThreadPersistent(this))),
-                 /*is_sink_secure=*/false);
-  return ScriptPromise::CastUndefined(script_state);
-}
-
-ScriptPromise MediaStreamVideoTrackUnderlyingSource::Cancel(
-    ScriptState* script_state,
-    ScriptValue reason) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  DisconnectFromTrack();
-  return ScriptPromise::CastUndefined(script_state);
-}
-
 void MediaStreamVideoTrackUnderlyingSource::Trace(Visitor* visitor) const {
+  FrameQueueUnderlyingSource::Trace(visitor);
   visitor->Trace(track_);
-  UnderlyingSourceBase::Trace(visitor);
-}
-
-double MediaStreamVideoTrackUnderlyingSource::DesiredSizeForTesting() const {
-  return Controller()->DesiredSize();
-}
-
-void MediaStreamVideoTrackUnderlyingSource::ContextDestroyed() {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  UnderlyingSourceBase::ContextDestroyed();
-  queue_.clear();
-}
-
-void MediaStreamVideoTrackUnderlyingSource::Close() {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  DisconnectFromTrack();
-  if (Controller())
-    Controller()->Close();
-  queue_.clear();
 }
 
 std::unique_ptr<ReadableStreamTransferringOptimizer>
 MediaStreamVideoTrackUnderlyingSource::GetStreamTransferOptimizer() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   auto stream_transferred_cb = [](MediaStreamVideoTrackUnderlyingSource* self) {
     if (self)
-      self->stream_was_transferred_ = true;
+      self->SetStreamWasTransferred();
   };
 
   return std::make_unique<StreamTransferNotifier>(
-      main_task_runner_,
+      Thread::Current()->GetTaskRunner(),
       CrossThreadBindOnce(stream_transferred_cb,
                           WrapCrossThreadWeakPersistent(this)));
 }
@@ -144,56 +78,26 @@
     std::vector<scoped_refptr<media::VideoFrame>> /*scaled_media_frames*/,
     base::TimeTicks estimated_capture_time) {
   // The scaled video frames are currently ignored.
-  PostCrossThreadTask(
-      *main_task_runner_, FROM_HERE,
-      CrossThreadBindOnce(
-          &MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrackOnMainThread,
-          WrapCrossThreadPersistent(this), std::move(media_frame),
-          estimated_capture_time));
+  QueueFrame(std::move(media_frame));
 }
 
-void MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrackOnMainThread(
-    scoped_refptr<media::VideoFrame> media_frame,
-    base::TimeTicks /*estimated_capture_time*/) {
-  DCHECK(main_task_runner_->BelongsToCurrentThread());
-  DCHECK_LE(queue_.size(), max_queue_size_);
+bool MediaStreamVideoTrackUnderlyingSource::StartFrameDelivery() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  MediaStreamVideoTrack* video_track = MediaStreamVideoTrack::From(track_);
+  if (!video_track)
+    return false;
 
-  // If the |queue_| is empty and the consumer has signaled a pull, bypass
-  // |queue_| and send the frame directly to the stream controller.
-  if (queue_.empty() && is_pending_pull_) {
-    SendFrameToStream(std::move(media_frame));
-    return;
-  }
-
-  if (queue_.size() == max_queue_size_)
-    queue_.pop_front();
-
-  queue_.push_back(std::move(media_frame));
-  if (is_pending_pull_) {
-    ProcessPullRequest();
-  }
+  ConnectToTrack(WebMediaStreamTrack(track_),
+                 ConvertToBaseRepeatingCallback(CrossThreadBindRepeating(
+                     &MediaStreamVideoTrackUnderlyingSource::OnFrameFromTrack,
+                     WrapCrossThreadPersistent(this))),
+                 /*is_sink_secure=*/false);
+  return true;
 }
 
-void MediaStreamVideoTrackUnderlyingSource::ProcessPullRequest() {
-  DCHECK(!queue_.empty());
-  SendFrameToStream(std::move(queue_.front()));
-  queue_.pop_front();
-}
-
-void MediaStreamVideoTrackUnderlyingSource::SendFrameToStream(
-    scoped_refptr<media::VideoFrame> media_frame) {
-  DCHECK(media_frame);
-  if (!Controller())
-    return;
-
-  VideoFrame* video_frame = MakeGarbageCollected<VideoFrame>(
-      std::move(media_frame), GetExecutionContext());
-
-  if (stream_was_transferred_)
-    video_frame->handle()->SetCloseOnClone();
-
-  Controller()->Enqueue(video_frame);
-  is_pending_pull_ = false;
+void MediaStreamVideoTrackUnderlyingSource::StopFrameDelivery() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DisconnectFromTrack();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
index 5c094588..7e7d1e6 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source.h
@@ -5,19 +5,19 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_TRACK_UNDERLYING_SOURCE_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_VIDEO_TRACK_UNDERLYING_SOURCE_H_
 
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_sink.h"
 #include "third_party/blink/renderer/core/streams/readable_stream_transferring_optimizer.h"
-#include "third_party/blink/renderer/core/streams/underlying_source_base.h"
+#include "third_party/blink/renderer/modules/mediastream/frame_queue_underlying_source.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/platform/wtf/deque.h"
+#include "third_party/blink/renderer/platform/heap/impl/garbage_collected.h"
 
 namespace blink {
 
 class MediaStreamComponent;
 
 class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSource
-    : public UnderlyingSourceBase,
+    : public VideoFrameQueueUnderlyingSource,
       public MediaStreamVideoSink {
  public:
   explicit MediaStreamVideoTrackUnderlyingSource(ScriptState*,
@@ -28,53 +28,26 @@
   MediaStreamVideoTrackUnderlyingSource& operator=(
       const MediaStreamVideoTrackUnderlyingSource&) = delete;
 
-  // UnderlyingSourceBase
-  ScriptPromise pull(ScriptState*) override;
-  ScriptPromise Start(ScriptState*) override;
-  ScriptPromise Cancel(ScriptState*, ScriptValue reason) override;
-
-  // ExecutionLifecycleObserver
-  void ContextDestroyed() override;
-
   MediaStreamComponent* Track() const { return track_.Get(); }
-  wtf_size_t MaxQueueSize() const { return max_queue_size_; }
 
-  bool IsPendingPullForTesting() const { return is_pending_pull_; }
-  const Deque<scoped_refptr<media::VideoFrame>>& QueueForTesting() const {
-    return queue_;
-  }
-  double DesiredSizeForTesting() const;
-
-  void Close();
   void Trace(Visitor*) const override;
 
   std::unique_ptr<ReadableStreamTransferringOptimizer>
   GetStreamTransferOptimizer();
 
  private:
+  // FrameQueueUnderlyingSource implementation.
+  bool StartFrameDelivery() override;
+  void StopFrameDelivery() override;
+
   void OnFrameFromTrack(
       scoped_refptr<media::VideoFrame> media_frame,
       std::vector<scoped_refptr<media::VideoFrame>> scaled_media_frames,
       base::TimeTicks estimated_capture_time);
-  void OnFrameFromTrackOnMainThread(
-      scoped_refptr<media::VideoFrame> media_frame,
-      base::TimeTicks estimated_capture_time);
-  void SendFrameToStream(scoped_refptr<media::VideoFrame> media_frame);
-  void ProcessPullRequest();
 
-  // Used when a stream endpoint was transferred to another realm, to
-  // automatically close frames as they are posted to the other stream.
-  bool stream_was_transferred_ = false;
-
-  const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   const Member<MediaStreamComponent> track_;
 
-  // An internal deque prior to the stream controller's queue. It acts as a ring
-  // buffer and allows dropping old frames instead of new ones in case frames
-  // accumulate due to slow consumption.
-  Deque<scoped_refptr<media::VideoFrame>> queue_;
-  const wtf_size_t max_queue_size_;
-  bool is_pending_pull_ = false;
+  SEQUENCE_CHECKER(sequence_checker_);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
index 96718a7..9cb4d30 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track_underlying_source_test.cc
@@ -192,6 +192,7 @@
   ScriptState* script_state = v8_scope.GetScriptState();
   auto* track = CreateTrack(v8_scope.GetExecutionContext());
   auto* source = CreateSource(script_state, track);
+
   // Create a stream to ensure there is a controller associated to the source.
   ReadableStream::CreateWithCountQueueingStrategy(script_state, source, 0);
 
diff --git a/third_party/blink/renderer/modules/modules_export.h b/third_party/blink/renderer/modules/modules_export.h
index 922794bd..73146ad 100644
--- a/third_party/blink/renderer/modules/modules_export.h
+++ b/third_party/blink/renderer/modules/modules_export.h
@@ -42,4 +42,27 @@
 
 #endif  // !defined(COMPONENT_BUILD)
 
+//
+// MODULES_EXTERN_TEMPLATE_EXPORT
+// MODULES_TEMPLATE_EXPORT
+//
+#if BLINK_MODULES_IMPLEMENTATION
+
+#if defined(COMPILER_MSVC)
+#define MODULES_EXTERN_TEMPLATE_EXPORT
+#define MODULES_TEMPLATE_EXPORT MODULES_EXPORT
+#endif
+
+#if defined(COMPILER_GCC)
+#define MODULES_EXTERN_TEMPLATE_EXPORT MODULES_EXPORT
+#define MODULES_TEMPLATE_EXPORT
+#endif
+
+#else  // BLINK_MODULES_IMPLEMENTATION
+
+#define MODULES_EXTERN_TEMPLATE_EXPORT MODULES_EXPORT
+#define MODULES_TEMPLATE_EXPORT
+
+#endif  // BLINK_MODULES_IMPLEMENTATION
+
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MODULES_EXPORT_H_
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
index 2c10988..0cf16ee 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_node.cc
@@ -147,35 +147,17 @@
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
                      "ScriptProcessorHandler::Process");
 
-  // The main thread might be accessing the shared buffers. If so, silence
-  // the output and return.
-  MutexTryLocker try_locker(process_event_lock_);
-  if (!try_locker.Locked()) {
-    TRACE_EVENT_INSTANT0(
-        TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
-        "ScriptProcessorHandler::Process - tryLock failed (silence)",
-        TRACE_EVENT_SCOPE_THREAD);
-    TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
-                     "ScriptProcessorHandler::Process");
-
-    Output(0).Bus()->Zero();
-    return;
-  }
-
-  // Discussion about inputs and outputs:
   // As in other AudioNodes, ScriptProcessorNode uses an AudioBus for its input
-  // and output (see inputBus and outputBus below).  Additionally, there is a
-  // double-buffering for input and output which is exposed directly to
-  // JavaScript (see inputBuffer and outputBuffer below).  This node is the
-  // producer for inputBuffer and the consumer for outputBuffer.  The JavaScript
-  // code is the consumer of inputBuffer and the producer for outputBuffer.
+  // and output (i.e. |input_bus| and |output_bus|). Additionally, there is a
+  // double-buffering for input and output that are exposed directly to
+  // JavaScript (i.e. |inputBuffer| and |outputBuffer| in
+  // |AudioProcessingEvent|). This node is the producer for |inputBuffer| and
+  // the consumer for |outputBuffer|. The |AudioProcessingEvent| is the
+  // consumer of |inputBuffer| and the producer for |outputBuffer|.
 
-  // Get input and output busses.
   scoped_refptr<AudioBus> input_bus = Input(0).Bus();
   AudioBus* output_bus = Output(0).Bus();
 
-  // Get input and output buffers. We double-buffer both the input and output
-  // sides.
   uint32_t double_buffer_index = this->DoubleBufferIndex();
   DCHECK_LT(double_buffer_index, 2u);
   DCHECK_LT(double_buffer_index, shared_input_buffers_.size());
@@ -186,52 +168,71 @@
   SharedAudioBuffer* shared_output_buffer =
       shared_output_buffers_.at(double_buffer_index).get();
 
-  // Check the consistency of input and output buffers.
-  uint32_t number_of_input_channels = internal_input_bus_->NumberOfChannels();
   bool buffers_are_good =
       shared_output_buffer && BufferSize() == shared_output_buffer->length() &&
       buffer_read_write_index_ + frames_to_process <= BufferSize();
 
-  // If the number of input channels is zero, it's ok to have inputBuffer = 0.
   if (internal_input_bus_->NumberOfChannels()) {
-    buffers_are_good = buffers_are_good && shared_input_buffer &&
-                       BufferSize() == shared_input_buffer->length();
+    // If the number of input channels is zero, the zero length |inputBuffer|
+    // is fine.
+    buffers_are_good = buffers_are_good &&
+      shared_input_buffer && BufferSize() == shared_input_buffer->length();
   }
 
   DCHECK(buffers_are_good);
 
-  // We assume that bufferSize() is evenly divisible by framesToProcess - should
-  // always be true, but we should still check.
+  // |BufferSize()| should be evenly divisible by |frames_to_process|.
   DCHECK_GT(frames_to_process, 0u);
   DCHECK_GE(BufferSize(), frames_to_process);
   DCHECK_EQ(BufferSize() % frames_to_process, 0u);
 
+  uint32_t number_of_input_channels = internal_input_bus_->NumberOfChannels();
   uint32_t number_of_output_channels = output_bus->NumberOfChannels();
-
   DCHECK_EQ(number_of_input_channels, number_of_input_channels_);
   DCHECK_EQ(number_of_output_channels, number_of_output_channels_);
 
-  for (uint32_t i = 0; i < number_of_input_channels; ++i)
-    internal_input_bus_->SetChannelMemory(
-        i,
-        static_cast<float*>(shared_input_buffer->channels()[i].Data()) +
-            buffer_read_write_index_,
-        frames_to_process);
+  {
+    MutexTryLocker try_locker(GetBufferLock());
+    if (!try_locker.Locked()) {
+      // Failed to acquire the output buffer, so output silence.
+      TRACE_EVENT_INSTANT0(
+          TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+          "ScriptProcessorHandler::Process - tryLock failed (output)",
+          TRACE_EVENT_SCOPE_THREAD);
+      TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+                       "ScriptProcessorHandler::Process");
+      Output(0).Bus()->Zero();
+      return;
+    }
 
-  if (number_of_input_channels)
-    internal_input_bus_->CopyFrom(*input_bus);
+    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+                 "ScriptProcessorHandler::Process - data copy under lock",
+                 "double_buffer_index", double_buffer_index);
 
-  // Copy from the output buffer to the output.
-  for (uint32_t i = 0; i < number_of_output_channels; ++i) {
-    memcpy(output_bus->Channel(i)->MutableData(),
-           static_cast<float*>(shared_output_buffer->channels()[i].Data()) +
-               buffer_read_write_index_,
-           sizeof(float) * frames_to_process);
+    for (uint32_t i = 0; i < number_of_input_channels; ++i) {
+      float* destination =
+          static_cast<float*>(shared_input_buffer->channels()[i].Data()) +
+          buffer_read_write_index_;
+      const float* source = input_bus->Channel(i)->Data();
+      memcpy(destination, source, sizeof(float) * frames_to_process);
+    }
+
+    for (uint32_t i = 0; i < number_of_output_channels; ++i) {
+      float* destination = output_bus->Channel(i)->MutableData();
+      const float* source =
+          static_cast<float*>(shared_output_buffer->channels()[i].Data()) +
+          buffer_read_write_index_;
+      memcpy(destination, source, sizeof(float) * frames_to_process);
+    }
   }
 
-  // Update the buffering index.
+  // Update the buffer index for wrap-around.
   buffer_read_write_index_ =
       (buffer_read_write_index_ + frames_to_process) % BufferSize();
+  TRACE_EVENT_INSTANT1(
+      TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+      "ScriptProcessorHandler::Process", TRACE_EVENT_SCOPE_THREAD,
+      "buffer_read_write_index_", buffer_read_write_index_);
 
   // Fire an event and swap buffers when |buffer_read_write_index_| wraps back
   // around to 0. It means the current input and output buffers are full.
@@ -255,6 +256,7 @@
       waitable_event->Wait();
     }
 
+    // Update the double-buffering index.
     SwapBuffers();
   }
 
@@ -272,9 +274,6 @@
 
   // Avoid firing the event if the document has already gone away.
   if (GetNode()) {
-    // This synchronizes with process().
-    MutexLocker process_locker(process_event_lock_);
-
     // Calculate a playbackTime with the buffersize which needs to be processed
     // each time onaudioprocess is called.  The outputBuffer being passed to JS
     // will be played after exhuasting previous outputBuffer by
@@ -530,64 +529,86 @@
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
                "ScriptProcessorNode::DispatchEvent");
 
-  AudioBuffer* backing_input_buffer =
-      input_buffers_.at(double_buffer_index).Get();
+  ScriptProcessorHandler& handler =
+      static_cast<ScriptProcessorHandler&>(Handler());
 
-  // The backing buffer can be nullptr, when the number of input channels is 0.
-  if (backing_input_buffer) {
-    // Also the author code might have transferred |external_input_buffer| to
-    // other threads or replaced it with a different AudioBuffer object. Then
-    // re-create a new buffer instance.
-    if (IsAudioBufferDetached(external_input_buffer_) ||
-        !BufferTopologyMatches(backing_input_buffer,
-                               external_input_buffer_)) {
-      TRACE_EVENT0(
-          TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
-          "ScriptProcessorNode::DispatchEvent (create input AudioBuffer)");
-      external_input_buffer_ = AudioBuffer::Create(
-          backing_input_buffer->numberOfChannels(),
-          backing_input_buffer->length(),
-          backing_input_buffer->sampleRate());
-    }
+  {
+    MutexLocker locker(handler.GetBufferLock());
+    TRACE_EVENT1(
+        TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+        "ScriptProcessorNode::DispatchEvent (copy input under lock)",
+        "double_buffer_index", double_buffer_index);
 
-    for (unsigned channel = 0;
-         channel < backing_input_buffer->numberOfChannels(); ++channel) {
-      const float* source = static_cast<float*>(
-          backing_input_buffer->getChannelData(channel)->buffer()->Data());
-      float* destination = static_cast<float*>(
-          external_input_buffer_->getChannelData(channel)->buffer()->Data());
-      memcpy(destination, source,
-             backing_input_buffer->length() * sizeof(float));
+    AudioBuffer* backing_input_buffer =
+        input_buffers_.at(double_buffer_index).Get();
+
+    // The backing buffer can be |nullptr|, when the number of input channels
+    // is 0.
+    if (backing_input_buffer) {
+      // Also the author code might have transferred |external_input_buffer| to
+      // other threads or replaced it with a different AudioBuffer object. Then
+      // re-create a new buffer instance.
+      if (IsAudioBufferDetached(external_input_buffer_) ||
+          !BufferTopologyMatches(backing_input_buffer,
+                                external_input_buffer_)) {
+        TRACE_EVENT0(
+            TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+            "ScriptProcessorNode::DispatchEvent (create input AudioBuffer)");
+        external_input_buffer_ = AudioBuffer::Create(
+            backing_input_buffer->numberOfChannels(),
+            backing_input_buffer->length(),
+            backing_input_buffer->sampleRate());
+      }
+
+      for (unsigned channel = 0;
+          channel < backing_input_buffer->numberOfChannels(); ++channel) {
+        const float* source = static_cast<float*>(
+            backing_input_buffer->getChannelData(channel)->buffer()->Data());
+        float* destination = static_cast<float*>(
+            external_input_buffer_->getChannelData(channel)->buffer()->Data());
+        memcpy(destination, source,
+               backing_input_buffer->length() * sizeof(float));
+      }
     }
   }
 
+  external_output_buffer_->Zero();
+
   AudioNode::DispatchEvent(*AudioProcessingEvent::Create(
       external_input_buffer_, external_output_buffer_, playback_time));
 
-  AudioBuffer* backing_output_buffer =
-      output_buffers_.at(double_buffer_index).Get();
+  {
+    MutexLocker locker(handler.GetBufferLock());
+    TRACE_EVENT1(
+        TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+        "ScriptProcessorNode::DispatchEvent (copy output under lock)",
+        "double_buffer_index", double_buffer_index);
 
-  if (backing_output_buffer) {
-    if (IsAudioBufferDetached(external_output_buffer_) ||
-        !BufferTopologyMatches(backing_output_buffer,
-                               external_output_buffer_)) {
-      TRACE_EVENT0(
-          TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
-          "ScriptProcessorNode::DispatchEvent (create output AudioBuffer)");
-      external_output_buffer_ = AudioBuffer::Create(
-          backing_output_buffer->numberOfChannels(),
-          backing_output_buffer->length(),
-          backing_output_buffer->sampleRate());
-    }
+    AudioBuffer* backing_output_buffer =
+        output_buffers_.at(double_buffer_index).Get();
 
-    for (unsigned channel = 0;
-         channel < backing_output_buffer->numberOfChannels(); ++channel) {
-      const float* source = static_cast<float*>(
-          external_output_buffer_->getChannelData(channel)->buffer()->Data());
-      float* destination = static_cast<float*>(
-          backing_output_buffer->getChannelData(channel)->buffer()->Data());
-      memcpy(destination, source,
-             backing_output_buffer->length() * sizeof(float));
+    if (backing_output_buffer) {
+      if (IsAudioBufferDetached(external_output_buffer_) ||
+          !BufferTopologyMatches(backing_output_buffer,
+                                 external_output_buffer_)) {
+        TRACE_EVENT0(
+            TRACE_DISABLED_BY_DEFAULT("webaudio.audionode"),
+            "ScriptProcessorNode::DispatchEvent (create output AudioBuffer)");
+        external_output_buffer_ = AudioBuffer::Create(
+            backing_output_buffer->numberOfChannels(),
+            backing_output_buffer->length(),
+            backing_output_buffer->sampleRate());
+      }
+
+      for (unsigned channel = 0;
+          channel < backing_output_buffer->numberOfChannels(); ++channel) {
+        const float* source = static_cast<float*>(
+            external_output_buffer_->getChannelData(channel)->buffer()->Data());
+        float* destination = static_cast<float*>(
+            backing_output_buffer->getChannelData(channel)->buffer()->Data());
+        memcpy(destination, source,
+               backing_output_buffer->length() * sizeof(float));
+      }
     }
   }
 }
diff --git a/third_party/blink/renderer/modules/webaudio/script_processor_node.h b/third_party/blink/renderer/modules/webaudio/script_processor_node.h
index 9ae1789..708378d 100644
--- a/third_party/blink/renderer/modules/webaudio/script_processor_node.h
+++ b/third_party/blink/renderer/modules/webaudio/script_processor_node.h
@@ -79,6 +79,8 @@
     return number_of_output_channels_;
   }
 
+  Mutex& GetBufferLock() { return buffer_lock_; }
+
  private:
   ScriptProcessorHandler(AudioNode&,
                          float sample_rate,
@@ -99,18 +101,17 @@
   void SwapBuffers() { double_buffer_index_ = 1 - double_buffer_index_; }
   uint32_t double_buffer_index_;
 
+  // Protects |shared_input_buffers| and |shared_output_buffers_|.
+  mutable Mutex buffer_lock_;
   WTF::Vector<std::unique_ptr<SharedAudioBuffer>> shared_input_buffers_;
   WTF::Vector<std::unique_ptr<SharedAudioBuffer>> shared_output_buffers_;
 
   uint32_t buffer_size_;
   uint32_t buffer_read_write_index_;
-
   uint32_t number_of_input_channels_;
   uint32_t number_of_output_channels_;
 
   scoped_refptr<AudioBus> internal_input_bus_;
-  // Synchronize process() with fireProcessEvent().
-  mutable Mutex process_event_lock_;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
diff --git a/third_party/blink/renderer/modules/webcodecs/BUILD.gn b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
index a575126..f03bd1d 100644
--- a/third_party/blink/renderer/modules/webcodecs/BUILD.gn
+++ b/third_party/blink/renderer/modules/webcodecs/BUILD.gn
@@ -32,7 +32,6 @@
     "decoder_template.h",
     "encoded_audio_chunk.cc",
     "encoded_audio_chunk.h",
-    "encoded_audio_metadata.h",
     "encoded_video_chunk.cc",
     "encoded_video_chunk.h",
     "encoder_base.cc",
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
index d343dd60..0c0950b 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.cc
@@ -13,9 +13,9 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_encoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_frame_init.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_audio_chunk_metadata.h"
 #include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
 namespace blink {
@@ -74,7 +74,7 @@
   };
 
   stall_request_processing_ = true;
-  produced_first_output_ = false;
+  first_output_after_configure_ = true;
   media_encoder_->Initialize(
       active_config_->options, std::move(output_cb),
       ConvertToBaseOnceCallback(CrossThreadBindOnce(
@@ -231,25 +231,27 @@
     uint32_t reset_count,
     media::EncodedAudioBuffer encoded_buffer,
     base::Optional<media::AudioEncoder::CodecDescription> codec_desc) {
+  DCHECK(active_config);
   if (!script_state_->ContextIsValid() || !output_callback_ ||
       state_.AsEnum() != V8CodecState::Enum::kConfigured ||
       reset_count != reset_count_)
     return;
 
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  EncodedAudioMetadata metadata;
-  metadata.timestamp = encoded_buffer.timestamp - base::TimeTicks();
+  auto timestamp = encoded_buffer.timestamp - base::TimeTicks();
   auto deleter = [](void* data, size_t length, void*) {
     delete[] static_cast<uint8_t*>(data);
   };
   ArrayBufferContents data(encoded_buffer.encoded_data.release(),
                            encoded_buffer.encoded_data_size, deleter);
   auto* dom_array = MakeGarbageCollected<DOMArrayBuffer>(std::move(data));
-  auto* chunk = MakeGarbageCollected<EncodedAudioChunk>(metadata, dom_array);
+  auto* chunk =
+      MakeGarbageCollected<EncodedAudioChunk>(timestamp, false, dom_array);
 
-  AudioDecoderConfig* decoder_config = nullptr;
-  if (!produced_first_output_ || codec_desc.has_value()) {
-    decoder_config = MakeGarbageCollected<AudioDecoderConfig>();
+  auto* metadata = MakeGarbageCollected<EncodedAudioChunkMetadata>();
+  if (first_output_after_configure_ || codec_desc.has_value()) {
+    first_output_after_configure_ = false;
+    auto* decoder_config = MakeGarbageCollected<AudioDecoderConfig>();
     decoder_config->setCodec(active_config->codec_string);
     decoder_config->setSampleRate(active_config->options.sample_rate);
     decoder_config->setNumberOfChannels(active_config->options.channels);
@@ -259,11 +261,11 @@
       decoder_config->setDescription(
           ArrayBufferOrArrayBufferView::FromArrayBuffer(desc_array_buf));
     }
-    produced_first_output_ = true;
+    metadata->setDecoderConfig(decoder_config);
   }
 
   ScriptState::Scope scope(script_state_);
-  output_callback_->InvokeAndReportException(nullptr, chunk, decoder_config);
+  output_callback_->InvokeAndReportException(nullptr, chunk, metadata);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/audio_encoder.h b/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
index f7bae002..f9e67f1 100644
--- a/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/audio_encoder.h
@@ -89,8 +89,6 @@
       uint32_t reset_count,
       media::EncodedAudioBuffer encoded_buffer,
       base::Optional<media::AudioEncoder::CodecDescription> codec_desc);
-
-  bool produced_first_output_ = false;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc
index 4356861..80df9382 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.cc
@@ -15,28 +15,28 @@
 
 EncodedAudioChunk* EncodedAudioChunk::Create(
     const EncodedAudioChunkInit* init) {
-  EncodedAudioMetadata metadata;
-  metadata.timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
-  metadata.key_frame = (init->type() == "key");
+  auto timestamp = base::TimeDelta::FromMicroseconds(init->timestamp());
+  bool key_frame = (init->type() == "key");
   DOMArrayPiece piece(init->data());
 
   // A full copy of the data happens here.
   auto* buffer = piece.IsNull()
                      ? nullptr
                      : DOMArrayBuffer::Create(piece.Data(), piece.ByteLength());
-  return MakeGarbageCollected<EncodedAudioChunk>(metadata, buffer);
+  return MakeGarbageCollected<EncodedAudioChunk>(timestamp, key_frame, buffer);
 }
 
-EncodedAudioChunk::EncodedAudioChunk(EncodedAudioMetadata metadata,
+EncodedAudioChunk::EncodedAudioChunk(base::TimeDelta timestamp,
+                                     bool key_frame,
                                      DOMArrayBuffer* buffer)
-    : metadata_(metadata), buffer_(buffer) {}
+    : timestamp_(timestamp), key_frame_(key_frame), buffer_(buffer) {}
 
 String EncodedAudioChunk::type() const {
-  return metadata_.key_frame ? "key" : "delta";
+  return key_frame_ ? "key" : "delta";
 }
 
 uint64_t EncodedAudioChunk::timestamp() const {
-  return metadata_.timestamp.InMicroseconds();
+  return timestamp_.InMicroseconds();
 }
 
 DOMArrayBuffer* EncodedAudioChunk::data() const {
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h
index c21e0aa..bc6b8c69 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk.h
@@ -7,7 +7,6 @@
 
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_piece.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
-#include "third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 
 namespace blink {
@@ -19,7 +18,9 @@
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  EncodedAudioChunk(EncodedAudioMetadata metadata, DOMArrayBuffer* buffer);
+  EncodedAudioChunk(base::TimeDelta timestamp,
+                    bool key_frame,
+                    DOMArrayBuffer* buffer);
 
   static EncodedAudioChunk* Create(const EncodedAudioChunkInit* init);
 
@@ -34,7 +35,8 @@
   }
 
  private:
-  EncodedAudioMetadata metadata_;
+  base::TimeDelta timestamp_;
+  bool key_frame_ = false;
   Member<DOMArrayBuffer> buffer_;
 };
 
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_metadata.idl b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_metadata.idl
new file mode 100644
index 0000000..38515199
--- /dev/null
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_metadata.idl
@@ -0,0 +1,9 @@
+// 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.
+
+// https://github.com/WICG/web-codecs
+
+dictionary EncodedAudioChunkMetadata {
+  AudioDecoderConfig decoderConfig;
+};
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl
index 719d4db3..3bfa143 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl
+++ b/third_party/blink/renderer/modules/webcodecs/encoded_audio_chunk_output_callback.idl
@@ -6,4 +6,4 @@
 
 [RuntimeEnabled=WebCodecs]
 callback EncodedAudioChunkOutputCallback =
-  void(EncodedAudioChunk output, optional AudioDecoderConfig decoder_config);
+  void(EncodedAudioChunk output, EncodedAudioChunkMetadata metadata);
diff --git a/third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h b/third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h
deleted file mode 100644
index 665ac85..0000000
--- a/third_party/blink/renderer/modules/webcodecs/encoded_audio_metadata.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_AUDIO_METADATA_H_
-#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_AUDIO_METADATA_H_
-
-#include "base/time/time.h"
-
-namespace blink {
-
-struct EncodedAudioMetadata {
-  bool key_frame = false;
-  base::TimeDelta timestamp;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBCODECS_ENCODED_AUDIO_METADATA_H_
diff --git a/third_party/blink/renderer/modules/webcodecs/encoder_base.h b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
index 7c5374e..bf4d384 100644
--- a/third_party/blink/renderer/modules/webcodecs/encoder_base.h
+++ b/third_party/blink/renderer/modules/webcodecs/encoder_base.h
@@ -128,6 +128,8 @@
   // till the current requests are finished.
   bool stall_request_processing_ = false;
 
+  bool first_output_after_configure_ = true;
+
   SEQUENCE_CHECKER(sequence_checker_);
 };
 
diff --git a/third_party/blink/renderer/modules/webcodecs/idls.gni b/third_party/blink/renderer/modules/webcodecs/idls.gni
index 46a701bc..75a9552 100644
--- a/third_party/blink/renderer/modules/webcodecs/idls.gni
+++ b/third_party/blink/renderer/modules/webcodecs/idls.gni
@@ -33,6 +33,7 @@
   "avc_encoder_config.idl",
   "encoded_audio_chunk_init.idl",
   "encoded_video_chunk_init.idl",
+  "encoded_audio_chunk_metadata.idl",
   "encoded_video_chunk_metadata.idl",
   "image_decode_options.idl",
   "image_decode_result.idl",
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index bf65851..f26aa80 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -579,6 +579,7 @@
             WrapCrossThreadPersistent(self->active_config_.Get()),
             self->reset_count_));
 
+    self->first_output_after_configure_ = true;
     self->media_encoder_->ChangeOptions(
         self->active_config_->options, std::move(output_cb),
         ConvertToBaseOnceCallback(CrossThreadBindOnce(
@@ -645,21 +646,24 @@
   auto* chunk = MakeGarbageCollected<EncodedVideoChunk>(
       output.timestamp, output.key_frame, dom_array);
 
-  auto* decoder_config = MakeGarbageCollected<VideoDecoderConfig>();
-  decoder_config->setCodec(active_config->codec_string);
-  decoder_config->setCodedHeight(active_config->options.frame_size.height());
-  decoder_config->setCodedWidth(active_config->options.frame_size.width());
-  if (codec_desc.has_value()) {
-    auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(),
-                                                  codec_desc.value().size());
-    decoder_config->setDescription(
-        ArrayBufferOrArrayBufferView::FromArrayBuffer(desc_array_buf));
-  }
-
   auto* metadata = MakeGarbageCollected<EncodedVideoChunkMetadata>();
-  metadata->setDecoderConfig(decoder_config);
   metadata->setTemporalLayerId(output.temporal_id);
 
+  if (first_output_after_configure_ || codec_desc.has_value()) {
+    first_output_after_configure_ = false;
+    auto* decoder_config = MakeGarbageCollected<VideoDecoderConfig>();
+    decoder_config->setCodec(active_config->codec_string);
+    decoder_config->setCodedHeight(active_config->options.frame_size.height());
+    decoder_config->setCodedWidth(active_config->options.frame_size.width());
+    if (codec_desc.has_value()) {
+      auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(),
+                                                    codec_desc.value().size());
+      decoder_config->setDescription(
+          ArrayBufferOrArrayBufferView::FromArrayBuffer(desc_array_buf));
+    }
+    metadata->setDecoderConfig(decoder_config);
+  }
+
   ScriptState::Scope scope(script_state_);
   output_callback_->InvokeAndReportException(nullptr, chunk, metadata);
 }
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
index b987497..c04dca4 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
@@ -169,8 +169,6 @@
     return;
 
   IntRect rect = Intersection(old_interest_rect, new_interest_rect);
-  // Avoid too big area as the following code is slow.
-  rect.Intersect(IntRect(rect.X(), rect.Y(), 1200, 6000));
   if (rect.IsEmpty())
     return;
 
@@ -197,6 +195,15 @@
   int mismatching_pixels = 0;
   static const int kMaxMismatchesToReport = 50;
   for (int bitmap_y = 0; bitmap_y < rect.Height(); ++bitmap_y) {
+    // In the common case of no under-invalidation, memcmp/memset is much faster
+    // than the pixel-by-pixel comparison below.
+    void* new_row_addr = new_bitmap.pixmap().writable_addr(0, bitmap_y);
+    if (memcmp(old_bitmap.pixmap().addr(0, bitmap_y), new_row_addr,
+               new_bitmap.rowBytes()) == 0) {
+      memset(new_row_addr, 0, new_bitmap.rowBytes());
+      continue;
+    }
+
     int layer_y = bitmap_y + rect.Y();
     for (int bitmap_x = 0; bitmap_x < rect.Width(); ++bitmap_x) {
       int layer_x = bitmap_x + rect.X();
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 1a234b2..2b7a6bf 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -43,9 +43,6 @@
 crbug.com/1135676 external/wpt/css/css-ui/resize-child-will-change-transform.html [ Pass ]
 crbug.com/148499 external/wpt/svg/extensibility/foreignObject/will-change-in-foreign-object-paint-order.html [ Pass ]
 
-# Raster under-invalidation checking doesn't work for huge layers.
-paint/invalidation/raster-under-invalidation-checking.html [ Failure ]
-
 paint/invalidation/media-audio-no-spurious-repaints.html [ Failure ]
 
 # Outline paints incorrectly with columns. Needs LayoutNGBlockFragment.
diff --git a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
index a6f131b..0f1fe2e4 100644
--- a/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
+++ b/third_party/blink/web_tests/external/wpt/webcodecs/audio-encoder.any.js
@@ -183,7 +183,8 @@
 
   let encoder_init = {
     error: t.unreached_func("Encoder error"),
-    output: (chunk, config) => {
+    output: (chunk, metadata) => {
+      let config = metadata.decoderConfig;
       if (config)
         decoder.configure(config);
       decoder.decode(chunk);
@@ -254,7 +255,8 @@
 
   let init = {
     error: t.unreached_func("Encoder error"),
-    output: (chunk, config) => {
+    output: (chunk, metadata) => {
+      let config = metadata.decoderConfig;
       // Only the first invocation of the output callback is supposed to have
       // a |config| in it.
       output_count++;
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/__init__.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/__init__.py
+++ /dev/null
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/__init__.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/__init__.py
+++ /dev/null
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/connect.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/connect.py
deleted file mode 100644
index 219efdcd..0000000
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/bidi/new_session/connect.py
+++ /dev/null
@@ -1,36 +0,0 @@
-import pytest
-import asyncio
-import websockets
-import webdriver
-
-# classic session to enable bidi capability manually
-# Intended to be the first test in this file
-@pytest.mark.asyncio
-@pytest.mark.capabilities({"webSocketUrl": True})
-async def test_websocket_url_connect(session):
-    assert not isinstance(session, webdriver.BidiSession)
-    websocket_url = session.capabilities["webSocketUrl"]
-    async with websockets.connect(websocket_url) as websocket:
-        await websocket.send("Hello world!")
-
-# test bidi_session send
-# using bidi_session is the recommended way to test bidi
-@pytest.mark.asyncio
-async def test_bidi_session_send(bidi_session):
-    await bidi_session.websocket_transport.send("test_bidi_session: send")
-
-# bidi session following a bidi session with a different capabilities
-# to test session recreation
-@pytest.mark.asyncio
-@pytest.mark.capabilities({"acceptInsecureCerts": True})
-async def test_bidi_session_with_different_capability(bidi_session):
-    await bidi_session.websocket_transport.send("test_bidi_session: different capability")
-
-# classic session following a bidi session to test session
-# recreation
-# Intended to be the last test in this file to make sure
-# classic session is not impacted by bidi tests
-@pytest.mark.asyncio
-def test_classic_after_bidi_session(session):
-    assert not isinstance(session, webdriver.BidiSession)
-
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/new_session/websocket_url.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/new_session/websocket_url.py
deleted file mode 100644
index ff6d6b32..0000000
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/new_session/websocket_url.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from tests.support.asserts import assert_success
-
-def test_websocket_url(new_session, add_browser_capabilities):
-    response, _ = new_session({"capabilities": {
-        "alwaysMatch": add_browser_capabilities({"webSocketUrl": True})}})
-    value = assert_success(response)
-    assert value["capabilities"]["webSocketUrl"].startswith("ws://")
-
diff --git a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures.py b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures.py
index 0ecfcdb..888c42b 100644
--- a/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures.py
+++ b/third_party/blink/web_tests/external/wpt/webdriver/tests/support/fixtures.py
@@ -2,7 +2,6 @@
 import json
 import os
 
-import asyncio
 import pytest
 import webdriver
 
@@ -40,17 +39,6 @@
             metafunc.parametrize("capabilities", marker.args, ids=None)
 
 
-# Ensure that the event loop is restarted once per session rather than the default  of once per test
-# if we don't do this, tests will try to reuse a closed event loop and fail with an error that the "future
-# belongs to a different loop"
-@pytest.fixture(scope="session")
-def event_loop():
-    """Change event_loop fixture to session level."""
-    loop = asyncio.get_event_loop_policy().new_event_loop()
-    yield loop
-    loop.close()
-
-
 @pytest.fixture
 def add_event_listeners(session):
     """Register listeners for tracked events on element."""
@@ -123,23 +111,8 @@
     }
 
 
-async def reset_current_session_if_necessary(caps, request_bidi):
-    global _current_session
-
-    # If there is a session with different capabilities active or the current session
-    # is of different type than the one we would like to create, end it now.
-    if _current_session is not None:
-        is_bidi = isinstance(_current_session, webdriver.BidiSession)
-        if is_bidi != request_bidi or not _current_session.match(caps):
-            if is_bidi:
-                await _current_session.end()
-            else:
-                _current_session.end()
-            _current_session = None
-
-
 @pytest.fixture(scope="function")
-async def session(capabilities, configuration, request):
+def session(capabilities, configuration, request):
     """Create and start a session for a test that does not itself test session creation.
 
     By default the session will stay open after each test, but we always try to start a
@@ -154,7 +127,11 @@
     deep_update(caps, capabilities)
     caps = {"alwaysMatch": caps}
 
-    await reset_current_session_if_necessary(caps, False)
+    # If there is a session with different capabilities active, end it now
+    if _current_session is not None and (
+            caps != _current_session.requested_capabilities):
+        _current_session.end()
+        _current_session = None
 
     if _current_session is None:
         _current_session = webdriver.Session(
@@ -163,46 +140,6 @@
             capabilities=caps)
     try:
         _current_session.start()
-
-    except webdriver.error.SessionNotCreatedException:
-        if not _current_session.session_id:
-            raise
-
-    # Enforce a fixed default window size and position
-    _current_session.window.size = defaults.WINDOW_SIZE
-    _current_session.window.position = defaults.WINDOW_POSITION
-
-    yield _current_session
-
-    cleanup_session(_current_session)
-
-
-@pytest.fixture(scope="function")
-async def bidi_session(capabilities, configuration, request):
-    """Create and start a bidi session for a test that does not itself test
-    bidi session creation.
-    By default the session will stay open after each test, but we always try to start a
-    new one and assume that if that fails there is already a valid session. This makes it
-    possible to recover from some errors that might leave the session in a bad state, but
-    does not demand that we start a new session per test."""
-    global _current_session
-
-    # Update configuration capabilities with custom ones from the
-    # capabilities fixture, which can be set by tests
-    caps = copy.deepcopy(configuration["capabilities"])
-    deep_update(caps, capabilities)
-    caps = {"alwaysMatch": caps}
-
-    await reset_current_session_if_necessary(caps, True)
-
-    if _current_session is None:
-        _current_session = webdriver.BidiSession(
-            configuration["host"],
-            configuration["port"],
-            capabilities=caps)
-    try:
-        await _current_session.start()
-
     except webdriver.error.SessionNotCreatedException:
         if not _current_session.session_id:
             raise
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-composite-video-shadow.html b/third_party/blink/web_tests/fast/canvas/canvas-composite-video-shadow.html
index 37fd00ce..ed411dc 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-composite-video-shadow.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-composite-video-shadow.html
@@ -21,11 +21,7 @@
     <div>Test Results</div>
     <div><table id='outputtable'></table></div>
     <div>Test Video</div>
-    <div><video id="video">
-      <source src="resources/canvas_video.webm" type='video/webm' />
-      <source src="resources/canvas_video.mp4"  type='video/mp4' />
-      <source src="resources/canvas_video.ogv"  type='video/ogg' />
-    </video></div>
+    <div><video id="video"></video></div>
     <script type="application/x-javascript">
       function drawImage(context, compositeIndex, alpha) {
         context.globalCompositeOperation = compositeTypes[compositeIndex];
@@ -42,13 +38,9 @@
       function setupTest() {}
 
       var video = document.getElementById("video");
-      video.addEventListener("playing", playVideo, true);
+      video.requestVideoFrameCallback(runTest);
+      video.src = "resources/canvas_video.webm";
       video.play();
-
-      function playVideo() {
-        video.removeEventListener("playing", playVideo, true);
-        runTest();
-      }
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-composite-video.html b/third_party/blink/web_tests/fast/canvas/canvas-composite-video.html
index 63c761d4..0c4939f 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-composite-video.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-composite-video.html
@@ -21,11 +21,7 @@
     <div>Test Results</div>
     <div><table id='outputtable'></table></div>
     <div>Test Video</div>
-    <div><video id="video">
-      <source src="resources/canvas_video.webm" type='video/webm' />
-      <source src="resources/canvas_video.mp4"  type='video/mp4' />
-      <source src="resources/canvas_video.ogv"  type='video/ogg' />
-    </video></div>
+    <div><video id="video"></video></div>
     <script type="application/x-javascript">
       function drawImage(context, compositeIndex, alpha) {
         context.globalCompositeOperation = compositeTypes[compositeIndex];
@@ -38,15 +34,9 @@
       function setupTest() {}
 
       var video = document.getElementById("video");
-      video.addEventListener("playing", playVideo, true);
+      video.requestVideoFrameCallback(runTest);
+      video.src = "resources/canvas_video.webm";
       video.play();
-
-      function playVideo() {
-        video.removeEventListener("playing", playVideo, true);
-        // We cannot read pixel after drawing a video because of SecurityError:
-        // The canvas has been tainted by cross-origin data.
-        runTest();
-      }
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-video-resize.html b/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-video-resize.html
index fae42c8..95c6170 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-video-resize.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-video-resize.html
@@ -24,12 +24,8 @@
     for (var i = 0; i < data1.length; i++) {
         // data1[i] is strictly the same as data2[i] on software rendering.
         // But on GPU, the difference could be quite significant.
-        if (Math.abs(data1[i] - data2[i]) > 18) {
-            dataMatched = false;
-            break;
-        }
+        assert_approx_equals(data1[i], data2[i], 18);
     }
-    assert_true(dataMatched);
 }
 
 function generateTest()
@@ -52,8 +48,8 @@
 // HTMLVideoElement
 var video = document.createElement("video");
 video.preload = "auto";
-video.oncanplaythrough = t.step_func(function() {
+video.requestVideoFrameCallback(t.step_func(function() {
     return generateTest();
-});
-video.src = "../../compositing/resources/video.ogv";
+}));
+video.src = "../../media/content/test.webm";
 </script>
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-expected.png
deleted file mode 100644
index 50e6f75..0000000
--- a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-reset.html b/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-reset.html
index 6abd6a3..bea21765 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-reset.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video-reset.html
@@ -9,11 +9,7 @@
 </head>
 <body>
   <canvas id="canvas"></canvas>
-  <video id="video">
-    <source src="resources/canvas_video.webm" type='video/webm' />
-    <source src="resources/canvas_video.mp4"  type='video/mp4' />
-    <source src="resources/canvas_video.ogv"  type='video/ogg' />
-  </video>
+  <video id="video"></video>
   <script>
   var length = 150;
   var canvas = document.getElementById("canvas");
@@ -22,11 +18,11 @@
   var ctx = canvas.getContext("2d");
 
   var video = document.getElementById("video");
-  video.addEventListener("playing", drawImageToCanvas, true);
+  video.requestVideoFrameCallback(drawImageToCanvas);
+  video.src = "resources/canvas_video.webm";
   video.play();
 
   function drawImageToCanvas() {
-    video.removeEventListener("playing", drawImageToCanvas, true);
     ctx.fillStyle = "blue";
     ctx.fillRect(0, 0, length, length);
     ctx.drawImage(video, 0, 0);
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video.html b/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video.html
index f0a0374..f984de1 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-drawImage-video.html
@@ -9,11 +9,7 @@
 </head>
 <body>
   <canvas id="canvas"></canvas>
-  <video id="video">
-    <source src="resources/canvas_video.webm" type='video/webm' />
-    <source src="resources/canvas_video.mp4"  type='video/mp4' />
-    <source src="resources/canvas_video.ogv"  type='video/ogg' />
-  </video>
+  <video id="video"></video><
   <script>
   var length = 150;
   var canvas = document.getElementById("canvas");
@@ -22,11 +18,11 @@
   var ctx = canvas.getContext("2d");
 
   var video = document.getElementById("video");
-  video.addEventListener("playing", drawImageToCanvas, true);
+  video.requestVideoFrameCallback(drawImageToCanvas);
+  video.src = "resources/canvas_video.webm";
   video.play();
 
   function drawImageToCanvas() {
-    video.removeEventListener("playing", drawImageToCanvas, true);
     ctx.fillStyle = "blue";
     ctx.fillRect(0, 0, length, length);
     ctx.drawImage(video, 0, 0);
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/fast/canvas/canvas-pattern-video-expected.png
deleted file mode 100644
index f31bb59..0000000
--- a/third_party/blink/web_tests/fast/canvas/canvas-pattern-video-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-pattern-video.html b/third_party/blink/web_tests/fast/canvas/canvas-pattern-video.html
index c05cdec..1c9256b6 100644
--- a/third_party/blink/web_tests/fast/canvas/canvas-pattern-video.html
+++ b/third_party/blink/web_tests/fast/canvas/canvas-pattern-video.html
@@ -9,11 +9,7 @@
 </head>
 <body>
   <canvas id="canvas"></canvas>
-  <video id="video">
-    <source src="resources/canvas_video.webm" type='video/webm' />
-    <source src="resources/canvas_video.mp4"  type='video/mp4' />
-    <source src="resources/canvas_video.ogv"  type='video/ogg' />
-  </video>
+  <video id="video"></video>
   <script>
   if (window.testRunner)
     testRunner.waitUntilDone();
@@ -25,11 +21,11 @@
   var ctx = canvas.getContext("2d");
 
   var video = document.getElementById("video");
-  video.addEventListener("playing", drawImageToCanvas, true);
+  video.requestVideoFrameCallback(drawImageToCanvas);
+  video.src = "resources/canvas_video.webm";
   video.play();
 
   function drawImageToCanvas() {
-    video.removeEventListener("playing", drawImageToCanvas, true);
     ctx.fillStyle = "blue";
     ctx.fillRect(0, 0, length, length);
     ctx.fillStyle = ctx.createPattern(video, "no-repeat");
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/raster-under-invalidation-checking-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/raster-under-invalidation-checking-expected.txt
index 89a1f07d..bddc367 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/raster-under-invalidation-checking-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/raster-under-invalidation-checking-expected.txt
@@ -5,14 +5,10 @@
       "bounds": [800, 600],
       "contentsOpaque": true,
       "backgroundColor": "#FFFFFF",
-      "paintInvalidations": [
-        {
-          "object": "LayoutNGBlockFlow DIV id='target1'",
-          "rect": [18, 10, 60, 40],
-          "reason": "background"
-        }
+      "invalidations": [
+        [18, 10, 60, 40]
       ],
-      "underPaintInvalidations": [
+      "underInvalidations": [
         {
           "x": 18,
           "y": 10,
@@ -320,14 +316,10 @@
       "bounds": [60, 40],
       "contentsOpaque": true,
       "backgroundColor": "#008000",
-      "paintInvalidations": [
-        {
-          "object": "LayoutNGBlockFlow DIV id='target2'",
-          "rect": [0, 0, 60, 40],
-          "reason": "background"
-        }
+      "invalidations": [
+        [0, 0, 60, 40]
       ],
-      "underPaintInvalidations": [
+      "underInvalidations": [
         {
           "x": 0,
           "y": 0,
@@ -636,14 +628,10 @@
       "bounds": [150, 150],
       "contentsOpaque": true,
       "backgroundColor": "#FFFF00",
-      "paintInvalidations": [
-        {
-          "object": "LayoutNGBlockFlow (relative positioned) DIV id='target3'",
-          "rect": [40, 70, 60, 40],
-          "reason": "background"
-        }
+      "invalidations": [
+        [40, 70, 60, 40]
       ],
-      "underPaintInvalidations": [
+      "underInvalidations": [
         {
           "x": 40,
           "y": 70,
@@ -950,6 +938,7 @@
     {
       "name": "LayoutNGBlockFlow DIV id='scroller'",
       "bounds": [150, 150],
+      "contentsOpaqueForText": true,
       "drawsContent": false,
       "transform": 3
     },
@@ -975,318 +964,314 @@
       "name": "Scroll corner of LayoutNGBlockFlow DIV id='scroller'",
       "position": [135, 135],
       "bounds": [15, 15],
+      "contentsOpaque": true,
       "transform": 3
     },
     {
       "name": "LayoutNGBlockFlow DIV id='scroller'",
-      "position": [0, 5000],
-      "bounds": [135, 10000],
-      "backgroundColor": "#008000",
-      "paintInvalidations": [
-        {
-          "object": "LayoutNGBlockFlow (relative positioned) DIV id='target4'",
-          "rect": [40, 5010, 60, 40],
-          "reason": "background"
-        }
+      "bounds": [4000, 20000],
+      "contentsOpaqueForText": true,
+      "invalidations": [
+        [40, 10010, 60, 40]
       ],
-      "underPaintInvalidations": [
+      "underInvalidations": [
         {
           "x": 40,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 41,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 42,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 43,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 44,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 45,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 46,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 47,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 48,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 49,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 50,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 51,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 52,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 53,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 54,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 55,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 56,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 57,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 58,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 59,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 60,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 61,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 62,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 63,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 64,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 65,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 66,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 67,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 68,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 69,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 70,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 71,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 72,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 73,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 74,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 75,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 76,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 77,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 78,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 79,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 80,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 81,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 82,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 83,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 84,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 85,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 86,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 87,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 88,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         },
         {
           "x": 89,
-          "y": 5010,
+          "y": 10010,
           "oldPixel": "#0000FF",
           "newPixel": "#008000"
         }
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents-expected.txt
new file mode 100644
index 0000000..2aae990
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents-expected.txt
@@ -0,0 +1,12 @@
+Tests DOM.getContentQuads method with text inside display:contents elements.
+{
+    result : {
+        className : HTMLAnchorElement
+        description : a
+        objectId : <string>
+        subtype : node
+        type : object
+    }
+}
+Returned quads count: 1
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents.js b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents.js
new file mode 100644
index 0000000..9ba106327
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-display-contents.js
@@ -0,0 +1,18 @@
+(async function(testRunner) {
+  const { dp } = await testRunner.startURL('resources/display-contents.html',
+    'Tests DOM.getContentQuads method with text inside display:contents elements.');
+
+  await dp.DOM.enable();
+  const aLinkQuads = await quadsFor(`document.querySelector('a')`);
+  testRunner.log('Returned quads count: ' + aLinkQuads.length);
+
+  testRunner.completeTest();
+
+  async function quadsFor(expression) {
+    const { result } = await dp.Runtime.evaluate({ expression });
+    testRunner.log(result);
+    return (await dp.DOM.getContentQuads({ objectId: result.result.objectId })).result.quads;
+  }
+
+})
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text-expected.txt b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text-expected.txt
new file mode 100644
index 0000000..9cee67e6
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text-expected.txt
@@ -0,0 +1,22 @@
+Tests DOM.getContentQuads method with text nodes inside shadow DOM.
+{
+    result : {
+        className : HTMLAnchorElement
+        description : a#inner-link
+        objectId : <string>
+        subtype : node
+        type : object
+    }
+}
+Returned quads count: 1
+{
+    result : {
+        className : HTMLElement
+        description : my-link
+        objectId : <string>
+        subtype : node
+        type : object
+    }
+}
+Quads are equal: true
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text.js b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text.js
new file mode 100644
index 0000000..01c9893
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/dom-getContentQuads-slot-with-text.js
@@ -0,0 +1,20 @@
+(async function(testRunner) {
+  const { dp } = await testRunner.startURL('resources/shadow-dom-link.html',
+    'Tests DOM.getContentQuads method with text nodes inside shadow DOM.');
+
+  await dp.DOM.enable();
+  const aLinkQuads = await quadsFor(`document.querySelector('my-link').shadowRoot.querySelector('a')`);
+  testRunner.log('Returned quads count: ' + aLinkQuads.length);
+  const outerQuads = await quadsFor(`document.querySelector('my-link')`);
+  testRunner.log('Quads are equal: ' + (JSON.stringify(aLinkQuads) === JSON.stringify(outerQuads)));
+
+  testRunner.completeTest();
+
+  async function quadsFor(expression) {
+    const { result } = await dp.Runtime.evaluate({ expression });
+    testRunner.log(result);
+    return (await dp.DOM.getContentQuads({ objectId: result.result.objectId })).result.quads;
+  }
+
+})
+
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/resources/display-contents.html b/third_party/blink/web_tests/inspector-protocol/dom/resources/display-contents.html
new file mode 100644
index 0000000..feb004e3
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/resources/display-contents.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<style>
+b {
+  display: contents;
+}  
+</style>
+</head>
+<body>
+<a><b>My link</b></a>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/inspector-protocol/dom/resources/shadow-dom-link.html b/third_party/blink/web_tests/inspector-protocol/dom/resources/shadow-dom-link.html
new file mode 100644
index 0000000..7b5c906
--- /dev/null
+++ b/third_party/blink/web_tests/inspector-protocol/dom/resources/shadow-dom-link.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+<template id="my-link-template">
+  <a href="#" id="inner-link" onclick="clickCount++"><slot></slot></a>
+</template>
+<script>
+window.clickCount = 0;
+
+function addShadowDOM() {
+  const host = document.querySelector('my-link').attachShadow({mode: 'open'});
+  const template = document.getElementById('my-link-template');
+  host.appendChild(template.content.cloneNode(true));
+}
+</script>
+</head>
+<body onload="addShadowDOM()">
+<my-link>Sign up</my-link>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-drawImage-video-expected.png
index 88cdfd65..f80428f8 100644
--- a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-drawImage-video-expected.png
+++ b/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
index 88cdfd65..f80428f8 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..0232744
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..0232744
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..5f36585
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..5f36585
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..5f36585
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..5f36585
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac/fast/canvas/canvas-drawImage-video-expected.png
index 0232744..5f36585 100644
--- a/third_party/blink/web_tests/platform/mac/fast/canvas/canvas-drawImage-video-expected.png
+++ b/third_party/blink/web_tests/platform/mac/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
index 0232744..5f36585 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/win/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..ded2e0c
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/platform/win/fast/canvas/canvas-pattern-video-expected.png
similarity index 100%
rename from third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png
rename to third_party/blink/web_tests/platform/win/fast/canvas/canvas-pattern-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
index 3939e6e..e68ec73e 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
index 83bb2b7..470cb20 100644
--- a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..55e7b29
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png
new file mode 100644
index 0000000..40566c28
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-pattern-video-expected.png
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png
copy to third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-pattern-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
index 3939e6e..e68ec73e 100644
--- a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow-expected.png
index 83bb2b7..470cb20 100644
--- a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png
index d67d3cb..55e7b29 100644
--- a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
index d67d3cb..40566c28 100644
--- a/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-pattern-video-expected.png
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png
copy to third_party/blink/web_tests/platform/win/virtual/oopr-canvas2d/fast/canvas/canvas-pattern-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
index 3939e6e..e68ec73e 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
index 83bb2b7..470cb20 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-composite-video-shadow-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..55e7b29
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png
new file mode 100644
index 0000000..40566c28
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-drawImage-video-reset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-pattern-video-expected.png
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png
copy to third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-pattern-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
index 3939e6e..e68ec73e 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-composite-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png
new file mode 100644
index 0000000..55e7b29
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
index d67d3cb..40566c28 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-drawImage-video-reset-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png b/third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-pattern-video-expected.png
similarity index 100%
copy from third_party/blink/web_tests/platform/linux/fast/canvas/canvas-pattern-video-expected.png
copy to third_party/blink/web_tests/platform/win7/virtual/oopr-canvas2d/fast/canvas/canvas-pattern-video-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/broadcast-channel.html b/third_party/blink/web_tests/wpt_internal/prerender/broadcast-channel.html
new file mode 100644
index 0000000..21a2105
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/broadcast-channel.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Same-origin prerendering can access the BroadcastChannel API</title>
+<script src="/common/utils.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<body>
+<script>
+
+promise_test(async t => {
+  // The key used for storing a test result in the server.
+  const key = token();
+
+  const bc = new BroadcastChannel('prerender-channel');
+  const testReadText = "initiator writes to the broadcast channel";
+  const testWriteText = "prerender writes to the broadcast channel";
+  const gotMessage = new Promise(resolve => {
+    bc.addEventListener('message', e => {
+      resolve(e.data);
+    });
+  });
+
+  // Start prerendering a page that attempts to access the BroadcastChannel API.
+  startPrerendering(`resources/broadcast-channel-access.html?key=${key}`);
+
+  // Wait until the prerendered page connected to the channel.
+  const value = await nextValueFromServer(key);
+  assert_equals(
+    value, 'channel set up',
+    'Prerendering page should be able to create Broadcast Channel');
+
+  bc.postMessage(testReadText);
+  const testReadResult = await nextValueFromServer(key);
+  assert_equals(
+    testReadResult, testReadText,
+    'Prerendering page should be able to read data from Broadcast Channel'
+  );
+
+  const testWriteResult = await gotMessage;
+  assert_equals(
+    testWriteResult, testWriteText,
+    'Prerendering page should be able to write to Broadcast Channel');
+  bc.close();
+}, 'Prerendering pages should be able to access the BroadcastChannel API');
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/cookies.html b/third_party/blink/web_tests/wpt_internal/prerender/cookies.html
new file mode 100644
index 0000000..52e5f420
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/cookies.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Same-origin prerendering can access cookies</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<body>
+<script>
+
+promise_test(async t => {
+  const bc = new BroadcastChannel('prerender-channel');
+
+  const gotMessage = new Promise(resolve => {
+    bc.addEventListener('message', e => {
+      resolve(e.data);
+    }, {
+      once: true
+    });
+  });
+
+  const initiator_cookie = 'initiator_cookie=exist';
+  const prerender_cookie = 'prerender_cookie=exist';
+
+  document.cookie = initiator_cookie;
+
+  // Start prerendering a page that attempts to access cookies.
+  startPrerendering(`resources/cookies-access.html`);
+  const result = await gotMessage;
+  assert_equals(
+    result, initiator_cookie,
+    'prerendering page should be able to read from document cookies.');
+  assert_equals(
+    document.cookie, initiator_cookie + '; ' + prerender_cookie,
+    'prerendering page should be able to write to document cookies');
+  }, 'prerendering page should be able to access cookies');
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/indexeddb.html b/third_party/blink/web_tests/wpt_internal/prerender/indexeddb.html
new file mode 100644
index 0000000..8b7f12fc
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/indexeddb.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<title>Same-origin prerendering can access Indexed Database</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<script src="resources/indexedb-utils.js"></script>
+<body>
+<script>
+
+promise_test(async t => {
+  const bc = new BroadcastChannel('prerender-channel');
+
+  const gotMessage = new Promise(resolve => {
+    bc.addEventListener('message', e => {
+      resolve(e.data);
+    }, {
+      once: true
+    });
+  });
+
+  const db = await openIndexedDatabase();
+  assert_not_equals(db, null, 'Failed to open database.');
+  await addData(db, INITIATOR_KEY, INITIATOR_VALUE);
+
+  // Start prerendering a page that attempts to access the IndexedDB API.
+  startPrerendering(`resources/indexeddb-access.html`);
+
+  const prerenderReadResult = await gotMessage;
+  assert_equals(
+    prerenderReadResult, INITIATOR_VALUE,
+    'prerendering page should be able to read from Indexed DataBase');
+  const initiatorReadResult = await readData(db, PRERENDER_KEY);
+  assert_equals(
+    initiatorReadResult, PRERENDER_VALUE,
+    'prerendering page should be able to write to Indexed DataBase');
+  db.close();
+  bc.close();
+
+}, 'prerendering page should be able to access Indexed DataBase')
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/local-storage.html b/third_party/blink/web_tests/wpt_internal/prerender/local-storage.html
new file mode 100644
index 0000000..ab2dc9a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/local-storage.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Same-origin prerendering can access localStorage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<body>
+<script>
+
+promise_test(async t => {
+  const bc = new BroadcastChannel('prerender-channel');
+
+  const gotMessage = new Promise(resolve => {
+    bc.addEventListener('message', e => {
+      resolve(e.data);
+    }, {once:true});
+  });
+
+  const initialValue = "initial_set";
+  window.localStorage.setItem('initial', initialValue);
+
+  // Start prerendering a page that attempts to access localStorage API.
+  startPrerendering(`resources/local-storage-access.html`);
+  const result = await gotMessage;
+  assert_equals(
+    result, initialValue,
+      'prerendering page should be able to read from local storage');
+  assert_equals(
+      window.localStorage.getItem('prerender'), 'prerender_set',
+      'prerendering page should be able to write to local storage');
+}, 'prerendering page should be able to access local storage');
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/broadcast-channel-access.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/broadcast-channel-access.html
new file mode 100644
index 0000000..f6f815f
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/broadcast-channel-access.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<script>
+
+assert_true(document.prerendering);
+
+// Take a key used for storing a test result in the server.
+const params = new URLSearchParams(location.search);
+const key = params.get('key');
+
+const bc = new BroadcastChannel('prerender-channel');
+bc.postMessage('prerender writes to the broadcast channel');
+bc.addEventListener('message', e => {
+  // Send the initiator page the message this page received.
+  writeValueToServer(key, e.data);
+  bc.close();
+});
+
+// Inform the initiator page that the prerendering page has connected to the
+// Broadcast Channel.
+writeValueToServer(key, 'channel set up');
+
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/cookies-access.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/cookies-access.html
new file mode 100644
index 0000000..43b636c0
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/cookies-access.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const bc = new BroadcastChannel('prerender-channel');
+assert_true(document.prerendering);
+
+const result = document.cookie;
+document.cookie = "prerender_cookie=exist;path=/;";
+
+bc.postMessage(result);
+bc.close();
+
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/indexedb-utils.js b/third_party/blink/web_tests/wpt_internal/prerender/resources/indexedb-utils.js
new file mode 100644
index 0000000..c15ea40a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/indexedb-utils.js
@@ -0,0 +1,60 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+const STORAGE_NAME = 'prerender_test';
+const INITIATOR_KEY = 'initiator';
+const INITIATOR_VALUE = INITIATOR_KEY + '_set';
+const PRERENDER_KEY = 'prerender';
+const PRERENDER_VALUE = PRERENDER_KEY + '_set';
+
+async function openIndexedDatabase() {
+  return new Promise(resolve => {
+    const request = window.indexedDB.open(STORAGE_NAME);
+    request.onupgradeneeded = e => {
+      const db = e.target.result;
+      const objectStore =
+          db.createObjectStore(STORAGE_NAME, {autoIncrement: true});
+      objectStore.createIndex('key', 'key', {unique: true});
+    };
+    request.onerror = e => {
+      resolve(null);
+    };
+    request.onsuccess = e => {
+      resolve(e.target.result);
+    };
+  });
+}
+
+async function addData(db, key, value) {
+  return new Promise((resolve, reject) => {
+    const transaction = db.transaction(STORAGE_NAME, 'readwrite');
+    const request =
+        transaction.objectStore(STORAGE_NAME).add({'key': key, 'value': value});
+    // Use `transaction.oncomplete` rather than `request.onsuccess` to ensure
+    // that IndexedDB has flushed to disk.
+    transaction.oncomplete = e => {
+      resolve(true);
+    };
+    transaction.onerror = e => {
+      reject(e.target.error);
+    };
+  });
+}
+
+async function readData(db, key) {
+  return new Promise((resolve, reject) => {
+    const transaction = db.transaction(STORAGE_NAME);
+    const request = transaction.objectStore(STORAGE_NAME).index('key').get(key);
+    request.onsuccess = e => {
+      if (e.target.result) {
+        resolve(e.target.result.value);
+      } else {
+        reject(new Error('Empty result.'));
+      }
+    };
+    request.onerror = e => {
+      reject(e.target.error);
+    };
+  });
+}
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/indexeddb-access.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/indexeddb-access.html
new file mode 100644
index 0000000..20e2956c
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/indexeddb-access.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="indexedb-utils.js"></script>
+<script>
+
+assert_true(document.prerendering);
+
+async function operateDatabase(){
+  const bc = new BroadcastChannel('prerender-channel');
+
+  const db = await openIndexedDatabase();
+  assert_not_equals(db, null, 'Failed to open database.');
+
+  await addData(db, PRERENDER_KEY, PRERENDER_VALUE);
+  const result = await readData(db, INITIATOR_KEY);
+  bc.postMessage(result);
+  bc.close();
+  db.close();
+}
+
+operateDatabase();
+
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/local-storage-access.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/local-storage-access.html
new file mode 100644
index 0000000..00af1d5
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/local-storage-access.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const bc = new BroadcastChannel('prerender-channel');
+assert_true(document.prerendering);
+
+window.localStorage.setItem('prerender', 'prerender_set');
+const result = window.localStorage.getItem('initial');
+
+bc.postMessage(result);
+bc.close();
+
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
index a286a70..7ccc6f46 100644
--- a/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/avc_encoder_config.any.js
@@ -66,9 +66,7 @@
     assert_equals(startCode[2], 0x00, "startCode [2]");
     assert_equals(startCode[3], 0x01, "startCode [3]");
 
-    // No config needs to be emitted for annexb, but we always emit one for now.
     // There should not be an avcC 'description' with annexb.
-    // TODO: Update this if we only output configs when they change.
     assert_not_equals(output.config, null, "config annexb");
     assert_equals(output.config.description, undefined, "desc annexb");
 
diff --git a/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js b/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
index 79f79b0..c29d679 100644
--- a/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
+++ b/third_party/blink/web_tests/wpt_internal/webcodecs/basic_video_encoding.any.js
@@ -27,7 +27,7 @@
   const encoder_init = {
     output(chunk, metadata) {
       let config = metadata.decoderConfig;
-      if (decoder.state != "configured" || config.description) {
+      if (config) {
         decoder.configure(config);
       }
       decoder.decode(chunk);
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js
index d22548e..98ad90e6 100644
--- a/third_party/closure_compiler/externs/accessibility_private.js
+++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -458,6 +458,16 @@
 chrome.accessibilityPrivate.updateSelectToSpeakPanel = function(show, anchor, isPaused, speed) {};
 
 /**
+ * Shows a confirmation dialog.
+ * @param {string} title The title of the confirmation dialog.
+ * @param {string} description The description to show within the confirmation
+ *     dialog.
+ * @param {function(boolean): void} callback Called when the dialog is confirmed
+ *     or cancelled.
+ */
+chrome.accessibilityPrivate.showConfirmationDialog = function(title, description, callback) {};
+
+/**
  * Fired whenever ChromeVox should output introduction.
  * @type {!ChromeEvent}
  */
diff --git a/third_party/nearby/README.chromium b/third_party/nearby/README.chromium
index ebe07e8..57f8ca0 100644
--- a/third_party/nearby/README.chromium
+++ b/third_party/nearby/README.chromium
@@ -1,7 +1,7 @@
 Name: Nearby Connections Library
 Short Name: Nearby
 URL: https://github.com/google/nearby-connections
-Version: 8fafd3ef09818e1983945aa8be9663713c79c142
+Version: a7b99e7509c3734b94a151739bc4035de6497a37
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/r8/README.chromium b/third_party/r8/README.chromium
index 7235ab9..8ae5ce08 100644
--- a/third_party/r8/README.chromium
+++ b/third_party/r8/README.chromium
@@ -80,6 +80,7 @@
 
 How to file bugs against R8:
 * Copy & paste the failing ninja command (starts with proguard.py), and add --dump-inputs.
+  * This also works for dex.py, it produces d8inputs.zip
 * File bug at go/r8bug
 * Things to include (use discretion if some are not relevant):
   * src revision bug reproduces at
@@ -87,3 +88,8 @@
     * Prefer enable_chrome_android_internal=false
   * The r8inputs.zip from --dump-inputs
   * Any relevant dexdump analysis
+
+How to submit CLs to R8:
+* Request to be added to their allowlist in order to upload CLs.
+* After CLs are submitted, check the bots for build breakage.
+  * https://ci.chromium.org/p/r8/g/main_all/console
diff --git a/third_party/wpt_tools/PRESUBMIT.py b/third_party/wpt_tools/PRESUBMIT.py
index 1b4418d..42e84c4 100644
--- a/third_party/wpt_tools/PRESUBMIT.py
+++ b/third_party/wpt_tools/PRESUBMIT.py
@@ -20,8 +20,7 @@
     name='web_tests/external/PRESUBMIT_test.py',
     cmd=[abspath_to_test],
     kwargs={},
-    message=output_api.PresubmitError,
-    python3=True
+    message=output_api.PresubmitError
   )
   if input_api.verbose:
     print('Running ' + abspath_to_test)
@@ -46,7 +45,7 @@
         blink_path, 'web_tests', 'external', 'wpt')
     try:
       input_api.subprocess.check_output(
-          ['python3', wpt_exec_path, 'manifest', '--no-download',
+          ['python', wpt_exec_path, 'manifest', '--no-download',
            '--path', f.name, '--tests-root', external_wpt])
     except input_api.subprocess.CalledProcessError as exc:
       return [output_api.PresubmitError('wpt manifest failed:', long_text=exc.output)]
diff --git a/third_party/wpt_tools/README.chromium b/third_party/wpt_tools/README.chromium
index 0a9df00..0d19fa9b 100644
--- a/third_party/wpt_tools/README.chromium
+++ b/third_party/wpt_tools/README.chromium
@@ -1,7 +1,7 @@
 Name: web-platform-tests - Test Suites for Web Platform specifications
 Short Name: wpt
 URL: https://github.com/web-platform-tests/wpt/
-Version: f6a1fd063fd77ea5865c82682458ae4fb7d04bb3
+Version: 3eb2cdae07a8842112e804a59dbd0f9800c64e73
 License: LICENSES FOR W3C TEST SUITES (https://www.w3.org/Consortium/Legal/2008/03-bsd-license.html)
 License File: NOT_SHIPPED
 Security Critical: no
@@ -12,3 +12,7 @@
     for more details on maintenance.
 Local Modifications:
 - Removed all files except for those listed in wpt/WPTIncludeList.
+- Cherry-picked df9dc69c2340d79fbd56ee2adfa85ac8d4af0b93 temporarily to fix a
+  lint error blocking the importer.
+- Cherry-picked 9b5f845370d7c6fe83b51ceef3f91e42aa85bbc2 temporatily to resolve
+  https://crbug.com/1182579
diff --git a/third_party/wpt_tools/WPTIncludeList b/third_party/wpt_tools/WPTIncludeList
index 9b84204..0d381c4 100644
--- a/third_party/wpt_tools/WPTIncludeList
+++ b/third_party/wpt_tools/WPTIncludeList
@@ -175,7 +175,6 @@
 ./tools/third_party/webencodings/webencodings/tests.py
 ./tools/third_party/webencodings/webencodings/x_user_defined.py
 ./tools/webdriver/webdriver/__init__.py
-./tools/webdriver/webdriver/bidi.py
 ./tools/webdriver/webdriver/client.py
 ./tools/webdriver/webdriver/error.py
 ./tools/webdriver/webdriver/protocol.py
diff --git a/third_party/wpt_tools/checkout.sh b/third_party/wpt_tools/checkout.sh
index ce43eb7..24480dfe 100755
--- a/third_party/wpt_tools/checkout.sh
+++ b/third_party/wpt_tools/checkout.sh
@@ -9,7 +9,7 @@
 
 TARGET_DIR=$DIR/wpt
 REMOTE_REPO="https://github.com/web-platform-tests/wpt.git"
-WPT_HEAD=f6a1fd063fd77ea5865c82682458ae4fb7d04bb3
+WPT_HEAD=3eb2cdae07a8842112e804a59dbd0f9800c64e73
 
 function clone {
   # Remove existing repo if already exists.
diff --git a/third_party/wpt_tools/wpt/docs/commands.json b/third_party/wpt_tools/wpt/docs/commands.json
index 55408d8..f3494b8 100644
--- a/third_party/wpt_tools/wpt/docs/commands.json
+++ b/third_party/wpt_tools/wpt/docs/commands.json
@@ -3,6 +3,7 @@
     "path": "frontend.py",
     "script": "build",
     "help": "Build documentation",
+    "py3only": true,
     "virtualenv": true,
     "requirements": [
       "./requirements.txt"
diff --git a/third_party/wpt_tools/wpt/tools/certs/cacert.key b/third_party/wpt_tools/wpt/tools/certs/cacert.key
index 7b9bd97..6b240e5 100644
--- a/third_party/wpt_tools/wpt/tools/certs/cacert.key
+++ b/third_party/wpt_tools/wpt/tools/certs/cacert.key
@@ -1,30 +1,30 @@
 -----BEGIN ENCRYPTED PRIVATE KEY-----
-MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIy+AmMEgUCbACAggA
-MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECJTlAsVqhvE6BIIEyG++PNkc48P8
-oprMaYzGL0QsYQb7xLR/JYhWB2GVUZGTTYORqiUIgKUQkayG1cxO2Jyhqb+qZfdI
-gAt9x7uS6A2omVXCm0ZW1vl4NGOyNdHvTmCnf9EkCzqWYYUW0nxxdV6DsVtsOb1/
-gDJxo3n8CYue/5zGuOprQJRUZAHrvx2huKMzg3wxSzYOaRfYVy5N9dKbgroyd/Vy
-05H+k9HY9+YwhRhXSTyqMRNj3ftbizdoPFyWihVABUvan6ExScuXNbfVu/qwxG86
-WRAFr6qu1EBhe5OLttHDYnhr14HjSTkTp289wKAn9fOMzvUh0NEMTx5PgF3u0AK6
-edhtDrJwjgrRc6ENJw3mM6VGa/FxR0eRyp38+/MteYyfz5eVnyPnJw22uiBd8i2j
-6dzDS+zZMA3vmp2NdB3rbgleQ5sdNEqJz4GC/yqTtwGDwH+OrbMpl2BAn1ckz9R9
-2b+DYsstBtLDx+R6JOy/sOFGcZla5T5TYOVJWD5i4vnW216rK6Pi+mbXa9WzGfGH
-UmghkDDh7iLYIBT3+YgEHqAeb+RKfeq7X3r6PBOAhavLp/4w2ZffywnyfxOxKQwE
-nb0bU8OPkPe3by3sbfS9H17729dTMMAJ3NGVjst2rEGYbDU/OZuBZzW3fwFnwKV2
-N3BTe3nPpZ/SXip7I6Hf+b6TNGeyVZUvBzw7spGGlXbbK76EdWY3dcs2OMH6JxUW
-Ib/bkNqclqSeXYFigzDozAuBJ2cM0TXxhnvLLuLLgL4+kH/d0tdCLJLNSqDy4Q+N
-GOFWZGtaowGuhpblGsAC/Z2wdPJ+fVQxGbHfGOttyoxCdfNfSclk7KuJFVQCGn1H
-aBvZfr1bf+o+mxuDmaDKFyb3fGQ55AgAdno5NxEInSofuopAefNxwfGzhTYmnAdF
-JY6WvXisz57EW9SjEvGHJMRREYw9a8tPKCOXa9CgPFsVdhPA+cFaBI3qDoY9E6rv
-cYdhXKatnORDHTQXPJz241cJK1yz6VDqAzExQlXli+dSqLl04X/3hAjIAMtDeeCc
-7F3U9XLkMIAiU3GKHIA0mq8wkTucOd7EVV+TS+i4e9MBIRueNyEd4u6m04G7Y4kf
-pkGowONXy1CETy4RoRNJi+nGC7TwCLzbEg6Sb9xs9q2lLh/cAiqdArPk9vLNe9Gh
-YSlcwN4WSPtQTN4hjiBhWe7O9Ux6f2llptyQhCzpb58h7IOQgTUcHOENoxUnVQwS
-RYsj+29aAYcLI+5NJzMwYXNR3Fdb3sDUn16f/NsfZUpxFzmu7zSrt7SJJfFasMN3
-EjwuSoEtVdwT7+IOO8A9gRuh5JRjuFYx252Mc0HY/R3qlTwrBNXyUUyFUO8t6TYN
-gxpJEKFEcsgUe+O345PrwzX+lbs9Vqvz52XO+aKsVDmbjTzWV3MnSPZcBnw1GTtq
-uKGJYDOCDhV7R8IElf87xQz6z6qNYDfAjlcxfeJK5V6U07Qwi4pxvoychK/4hQ7q
-X8mHWDMdyTGqED191NcI0EMHu6cjm5JSs7gXQibYrRaUGXcgk50o+LE6hIyd4VC1
-vmkKK48mcfi4GFFtmfiWX4vDK8Qzs2/PZNZURc3zgXxu4CtopFnL5SX+ZOAMSWUo
-DV8CBNpQbBi6sYo4aHNB3g==
+MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQI666o+tmBgXYCAggA
+MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECILZgh0KpE9MBIIEyCgMCCFkSlDm
+wPDpQ0rFCyQyAcdP5HMnLM/W+2z5TYDqdhtLd+XqD2lGqr4lCd33CoDubRxZoU/t
+VQ0TuDQcfhCz8HG6nXMpai2NDrc5Ot29fVFdMFkk8na17RhMKUc6Gan/TDi+E4i8
+e2YakJ5JgaBUFBf/jyqJfLsYJezNFhn5+nCsz+KbZBoht2B+W/rq/FAUzwPGJ+Yc
+8J2gVcuRUctXwS47yI8aklXhIhwmL89Ioad3rpypeDX3tu5TeG2nv/d1uV3/FngC
+/18b4eJz6dpqdTVN5Uoa3NjHjY8a8mcBvWKBL6mWy2dTVl9W8wdgtVkvc0PsF3Pu
+oJy5oeWhP6dSqAvDHTDXa38rt3H9IRmTsIXd0VVOIhFjg8tDQTBR/CyJKp4JO8Oy
+y/RGZsdqcO03ujolWOlDY4Pi8e7JpHK+1kyhGOTimi/9JuWtiSp40gKDzylL1oaw
+hr1UaPHl/kA/gJgpDBKT+PXQt2Gm9qje9+B/U6zj31bVd0r1S0qMlXz81t/K+BcH
+u/5NaZsDXyE8rufyxAHPBKPxXMZONG7y6EbF868EHUrCAKlElfHtTnvP/k68V3eH
+GnVzsId8eirzutrRdugPXS7Pg1Uj1CL6Ga8ia9MfEIbSx/g2FQ9SMnurXVeWv1qM
+uMNZbRZUkkJD8T/VqB7ezrI553iTqZFGr6fQ0dyXBS0m1phPSkmPcqE42sYCIZcy
+KZGYeWS1LkFRoTxoAwRS8cf14NjmoG+Aby4iyB3QiMDOmsylZDF0vsYeUbUIkxyz
+GnSn2LaVpT3ZeuziLnNn3JaeIy946jEgZETvCDruurV5AoAb9pXG2Xuysevx/AuV
+Owzz82PqG308kq6xhcGNK+v9FRbagHaGZ5EG+iVUTjN348NjJIriDVdrH06fBqe+
+UFD9fAnN/Kj4dIJKUCun4UZiz2jHeNnAmkLwOZn/eTK1LbUrmT0J+3eupaF7zzxo
+CednARzHvAiEVAX8Wd5DauIjczesjdrO9ys7dTMeZeyV5t/s8W66TB6tVDIQwTIp
+3skdhbw22zI2lcrDhZbbYhwO9R6d4liENUZ/W5ISLDXn+w8kqqh1qXoE8vR0lxpy
+Oz27kg5DBqyUflx99HwLj8epMNpGzepMAeFXTd+gLFKk7gWtU/5mJItTEfBu8Iih
+FT3/eesClxxzBm2Mk1viv/iKspTH92+mKEz2ng6jONWxHXkfuxNWe4wX+KmO7s7P
+plzxnbr2TlNTewbuYqyKMwe9KOiXosdfxUkJq6D8R0bf+A69M/dggO7BVdxNfF71
++xdfqjWjll/58lQ15KdlycfVlYj6iDvK1ChrK4UH2myGbmhThIItezPm8Oo4i3I6
+iPk8ns/BqfFH2raE7cw7G3Ug6cEJrc8OG4c1mfBuHPAeDrCWNu7tEqwKrGGJVA3b
+1GiBo72z5XVOiP7lku708ZEfrzh2UGuSvx0gbpW3aMDNnVq2O6euIquZugeewckq
+2Ox9C1vADIA8ugRdHbSVRQE33YiU1QS3MvQ9TYW/Zv7Buuhrdk2S1WLRpkWw+qR6
+62EFFAw6wjpK/vciGucrV8GyybdxPFqZPMtQkghaOPUO84Qsx2rZXAR+4/gZuHGm
+v2L3tYSDEmQ+6kEynWtX/w==
 -----END ENCRYPTED PRIVATE KEY-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/cacert.pem b/third_party/wpt_tools/wpt/tools/certs/cacert.pem
index f7de3a3..fcc977b 100644
--- a/third_party/wpt_tools/wpt/tools/certs/cacert.pem
+++ b/third_party/wpt_tools/wpt/tools/certs/cacert.pem
@@ -1,176 +1,176 @@
 -----BEGIN CERTIFICATE-----
-MIJAhzCCP2+gAwIBAgIDDuxtMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
-Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTAzMTIwMDI3MzNaFw0yMjAzMTIwMDI3MzNa
+MIJAhzCCP2+gAwIBAgIDBlVFMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
+Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTAxMTIxNjEzMjhaFw0yMjAxMTIxNjEzMjha
 MB0xGzAZBgNVBAMMEndlYi1wbGF0Zm9ybS10ZXN0czCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAL28unmE4CuE50yyQ87wsXB1py9fN6vq9Re7kZrZVUbl
-p90KMqfb9mN9LTrJBZWygzz1lXEXTkYcsbmDhbxT5xpptpuK41EKl5GudhRd5k0V
-9urrVVANlWnFiaeSazFvqw0UPktrL2+C2VLXKy+b6cN7fUImS12+NGUkujmU11hY
-Yg3eP/habOoeKZG9gAnlIWLmFZ2GQ5qLru2IAH0OOL7C0w7JihKfYHI+Lq2a96KG
-FdPlOzDnUFidEqN3ssQIIX8C4jNhbQr2r7Magg8Lj4WeyrPlZGw2E/rGzmD1E1C3
-3KjOfBv0/AOprZGo1JsvsuYoq07Et/yx1WJwwm4fnO8CAwEAAaOCPc4wgj3KMAwG
-A1UdEwQFMAMBAf8wHQYDVR0OBBYEFL14OMI385wGqOs+r1qhiCQUhVu+MEcGA1Ud
-IwRAMD6AFL14OMI385wGqOs+r1qhiCQUhVu+oSGkHzAdMRswGQYDVQQDDBJ3ZWIt
-cGxhdGZvcm0tdGVzdHOCAw7sbTALBgNVHQ8EBAMCAgQwgh+bBgNVHR4Egh+SMIIf
-jqCCH4owE4IRd2ViLXBsYXRmb3JtLnRlc3QwF4IVbm90LXdlYi1wbGF0Zm9ybS50
-ZXN0MBeCFW9wNi53ZWItcGxhdGZvcm0udGVzdDAXghV3d3cud2ViLXBsYXRmb3Jt
-LnRlc3QwF4IVb3AxLndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wNy53ZWItcGxhdGZv
-cm0udGVzdDAXghVvcDgud2ViLXBsYXRmb3JtLnRlc3QwF4IVb3AyLndlYi1wbGF0
-Zm9ybS50ZXN0MBeCFW9wOS53ZWItcGxhdGZvcm0udGVzdDAXghVvcDUud2ViLXBs
-YXRmb3JtLnRlc3QwF4IVb3A0LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wMy53ZWIt
-cGxhdGZvcm0udGVzdDAYghZvcDQwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjEu
-d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdDAYghZv
-cDc5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzgud2ViLXBsYXRmb3JtLnRlc3Qw
-GIIWb3A3Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQzLndlYi1wbGF0Zm9ybS50
-ZXN0MBiCFm9wNDQud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNC53ZWItcGxhdGZv
-cm0udGVzdDAYghZvcDQ5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzYud2ViLXBs
-YXRmb3JtLnRlc3QwGIIWb3AyMS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDYwLndl
-Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1
-Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDk0LndlYi1wbGF0Zm9ybS50ZXN0MBiC
-Fm9wMTgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1Ny53ZWItcGxhdGZvcm0udGVz
-dDAYghZ3d3cyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTEud2ViLXBsYXRmb3Jt
-LnRlc3QwGIIWb3A0MS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ3LndlYi1wbGF0
-Zm9ybS50ZXN0MBiCFm9wNTIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyNS53ZWIt
-cGxhdGZvcm0udGVzdDAYghZvcDE2LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjYu
-d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxMC53ZWItcGxhdGZvcm0udGVzdDAYghZv
-cDY5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTIud2ViLXBsYXRmb3JtLnRlc3Qw
-GIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDc0LndlYi1wbGF0Zm9ybS50
-ZXN0MBiCFm9wODkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4NC53ZWItcGxhdGZv
-cm0udGVzdDAYghZvcDM3LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDUud2ViLXBs
-YXRmb3JtLnRlc3QwGIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDg2Lndl
-Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3Az
-NC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ4LndlYi1wbGF0Zm9ybS50ZXN0MBiC
-Fm9wNzUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1MC53ZWItcGxhdGZvcm0udGVz
-dDAYghZvcDIyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjMud2ViLXBsYXRmb3Jt
-LnRlc3QwGIIWb3A3My53ZWItcGxhdGZvcm0udGVzdDAYghZvcDIwLndlYi1wbGF0
-Zm9ybS50ZXN0MBiCFm9wOTIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzMi53ZWIt
-cGxhdGZvcm0udGVzdDAYghZvcDgyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTgu
-d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdDAYghZv
-cDMwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wODcud2ViLXBsYXRmb3JtLnRlc3Qw
-GIIWb3A3MC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY0LndlYi1wbGF0Zm9ybS50
-ZXN0MBiCFm9wMTEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNS53ZWItcGxhdGZv
-cm0udGVzdDAYghZvcDg1LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTgud2ViLXBs
-YXRmb3JtLnRlc3QwGIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDgzLndl
-Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2
-OC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDk5LndlYi1wbGF0Zm9ybS50ZXN0MBiC
-Fm9wMzkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1OS53ZWItcGxhdGZvcm0udGVz
-dDAYghZvcDk1LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTMud2ViLXBsYXRmb3Jt
-LnRlc3QwGIIWb3A2My53ZWItcGxhdGZvcm0udGVzdDAYghZvcDU0LndlYi1wbGF0
-Zm9ybS50ZXN0MBiCFm9wODgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5My53ZWIt
-cGxhdGZvcm0udGVzdDAYghZvcDI4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTEu
-d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2Ni53ZWItcGxhdGZvcm0udGVzdDAYghZv
-cDE5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTAud2ViLXBsYXRmb3JtLnRlc3Qw
-GIIWb3A4MC53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY3LndlYi1wbGF0Zm9ybS50
-ZXN0MBiCFm9wNjUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyNy53ZWItcGxhdGZv
-cm0udGVzdDAYghZvcDc2LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzIud2ViLXBs
-YXRmb3JtLnRlc3QwGIIWb3AyOS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDk3Lndl
-Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A1
-NS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ2LndlYi1wbGF0Zm9ybS50ZXN0MBiC
-Fm9wNzgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxNy53ZWItcGxhdGZvcm0udGVz
-dDAYghZvcDI0LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wODEud2ViLXBsYXRmb3Jt
-LnRlc3QwG4IZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDQubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0MBuCGW9wOC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZ
-d3d3Lnd3dy53ZWItcGxhdGZvcm0udGVzdDAbghlvcDkubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MBuCGXd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZb3AxLm5vdC13
-ZWItcGxhdGZvcm0udGVzdDAbghlvcDMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MBuC
-GW9wNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZb3AyLm5vdC13ZWItcGxhdGZv
-cm0udGVzdDAbghlvcDYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjYubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wNzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTQubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-Mjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTIubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTUubm90
+BQADggEPADCCAQoCggEBAKlAc+52QkFGs3xjT0OiT3t7HajqFqelNp5toVZfL/SF
+cXqvhldvWzlKs3XW4+OKnGQP1nB7qmZZ8GjSY02Nho36Vq+YdzmHIHYPZcAlfmNO
+6iY/nca7C9MEIVJvxQsG/C5ZUTkKJ93iDehGay5YF8wiIb+k6cmaV5cDs+oBwmwu
+X3hxsDjOklUYCVY4Wvd4fU/zR/LdI3QZTAlNa4eLu7v/8z0vo8vG7T8VS09mc6eh
+BjB0x1L7XE6n+4v3gGE8RbxeaIpZbv8vVWK1LLLQ01gCOiNFjuuD3VcBqnZTbV9/
+v4MqHrPFfZm1MxesB/kybMTve4Y6PjT1U3zgJsrV0UcCAwEAAaOCPc4wgj3KMAwG
+A1UdEwQFMAMBAf8wHQYDVR0OBBYEFNxtjWLdVJjIYBfC01Gzv3NbXJC5MEcGA1Ud
+IwRAMD6AFNxtjWLdVJjIYBfC01Gzv3NbXJC5oSGkHzAdMRswGQYDVQQDDBJ3ZWIt
+cGxhdGZvcm0tdGVzdHOCAwZVRTALBgNVHQ8EBAMCAgQwgh+bBgNVHR4Egh+SMIIf
+jqCCH4owE4IRd2ViLXBsYXRmb3JtLnRlc3QwF4IVb3A4LndlYi1wbGF0Zm9ybS50
+ZXN0MBeCFW9wNy53ZWItcGxhdGZvcm0udGVzdDAXghVvcDkud2ViLXBsYXRmb3Jt
+LnRlc3QwF4IVb3A0LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW5vdC13ZWItcGxhdGZv
+cm0udGVzdDAXghVvcDYud2ViLXBsYXRmb3JtLnRlc3QwF4IVb3AzLndlYi1wbGF0
+Zm9ybS50ZXN0MBeCFW9wMi53ZWItcGxhdGZvcm0udGVzdDAXghVvcDEud2ViLXBs
+YXRmb3JtLnRlc3QwF4IVd3d3LndlYi1wbGF0Zm9ybS50ZXN0MBeCFW9wNS53ZWIt
+cGxhdGZvcm0udGVzdDAYghZvcDg4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTgu
+d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4NS53ZWItcGxhdGZvcm0udGVzdDAYghZv
+cDg5LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjYud2ViLXBsYXRmb3JtLnRlc3Qw
+GIIWb3A3Mi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDI0LndlYi1wbGF0Zm9ybS50
+ZXN0MBiCFm9wNDEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A3OS53ZWItcGxhdGZv
+cm0udGVzdDAYghZvcDkxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTkud2ViLXBs
+YXRmb3JtLnRlc3QwGIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDYwLndl
+Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTgud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3Ay
+OC53ZWItcGxhdGZvcm0udGVzdDAYghZ3d3cxLndlYi1wbGF0Zm9ybS50ZXN0MBiC
+Fm9wMTQud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2OS53ZWItcGxhdGZvcm0udGVz
+dDAYghZvcDQwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNzQud2ViLXBsYXRmb3Jt
+LnRlc3QwGIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE4LndlYi1wbGF0
+Zm9ybS50ZXN0MBiCFm9wNzMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A3Ny53ZWIt
+cGxhdGZvcm0udGVzdDAYghZvcDEyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNTQu
+d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2My53ZWItcGxhdGZvcm0udGVzdDAYghZv
+cDcxLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTUud2ViLXBsYXRmb3JtLnRlc3Qw
+GIIWb3AxNi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDM2LndlYi1wbGF0Zm9ybS50
+ZXN0MBiCFm9wMjcud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyOS53ZWItcGxhdGZv
+cm0udGVzdDAYghZvcDk0LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDQud2ViLXBs
+YXRmb3JtLnRlc3QwGIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdDAYghZvcDg0Lndl
+Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2
+MS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDcwLndlYi1wbGF0Zm9ybS50ZXN0MBiC
+Fnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A0My53ZWItcGxhdGZvcm0udGVz
+dDAYghZvcDc4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjYud2ViLXBsYXRmb3Jt
+LnRlc3QwGIIWb3A3Ni53ZWItcGxhdGZvcm0udGVzdDAYghZvcDUyLndlYi1wbGF0
+Zm9ybS50ZXN0MBiCFm9wOTkud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4Ni53ZWIt
+cGxhdGZvcm0udGVzdDAYghZvcDQ2LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTcu
+d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdDAYghZv
+cDkzLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMTAud2ViLXBsYXRmb3JtLnRlc3Qw
+GIIWb3A1NS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDQ3LndlYi1wbGF0Zm9ybS50
+ZXN0MBiCFm9wNTEud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A0NS53ZWItcGxhdGZv
+cm0udGVzdDAYghZvcDgwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjgud2ViLXBs
+YXRmb3JtLnRlc3QwGIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdDAYghZvcDU3Lndl
+Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2
+Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDkyLndlYi1wbGF0Zm9ybS50ZXN0MBiC
+Fm9wMTUud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxMy53ZWItcGxhdGZvcm0udGVz
+dDAYghZvcDc1LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNjQud2ViLXBsYXRmb3Jt
+LnRlc3QwGIIWb3A5Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDM3LndlYi1wbGF0
+Zm9ybS50ZXN0MBiCFm9wNTYud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A2Mi53ZWIt
+cGxhdGZvcm0udGVzdDAYghZvcDgyLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMjUu
+d2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AxMS53ZWItcGxhdGZvcm0udGVzdDAYghZv
+cDUwLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzgud2ViLXBsYXRmb3JtLnRlc3Qw
+GIIWb3A4My53ZWItcGxhdGZvcm0udGVzdDAYghZvcDgxLndlYi1wbGF0Zm9ybS50
+ZXN0MBiCFm9wMjAud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AyMS53ZWItcGxhdGZv
+cm0udGVzdDAYghZvcDIzLndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wNDIud2ViLXBs
+YXRmb3JtLnRlc3QwGIIWb3AyMi53ZWItcGxhdGZvcm0udGVzdDAYghZvcDY1Lndl
+Yi1wbGF0Zm9ybS50ZXN0MBiCFm9wOTYud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3A4
+Ny53ZWItcGxhdGZvcm0udGVzdDAYghZvcDE5LndlYi1wbGF0Zm9ybS50ZXN0MBiC
+Fm9wNTMud2ViLXBsYXRmb3JtLnRlc3QwGIIWb3AzMC53ZWItcGxhdGZvcm0udGVz
+dDAYghZvcDQ4LndlYi1wbGF0Zm9ybS50ZXN0MBiCFm9wMzQud2ViLXBsYXRmb3Jt
+LnRlc3QwG4IZb3A2Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghlvcDMubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0MBuCGW9wMi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZ
+b3A1Lm5vdC13ZWItcGxhdGZvcm0udGVzdDAbghl3d3cubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MBuCGXd3dy53d3cud2ViLXBsYXRmb3JtLnRlc3QwG4IZb3A3Lm5vdC13
+ZWItcGxhdGZvcm0udGVzdDAbghlvcDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MBuC
+GW9wOC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwG4IZb3A5Lm5vdC13ZWItcGxhdGZv
+cm0udGVzdDAbghlvcDEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzYubm90
 LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wNjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-ODcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzEud3d3LndlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODMubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wODEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTkubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-NjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzYubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGnd3dy53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjQubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGnd3dy53d3cxLndlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wMTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-NzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjUubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDkubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDcubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wODIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-MTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjcubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wODkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODYubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wMjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjMubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wNjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-NDIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzQubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTMubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIubm90LXdlYi1w
+MByCGm9wNTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjQubm90LXdlYi1w
 bGF0Zm9ybS50ZXN0MByCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-Mzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzMubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTUubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wNTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTYubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wMTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-MTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIud3d3LndlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjEubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODAubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wOTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjcubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wNDMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-NTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDQubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wMTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTkubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wMjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODgubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wNjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-NDAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDYubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTYubm90
+OTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODMubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzMubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODEubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wNzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+Nzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDAubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjUubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dy53d3cyLndlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wODAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTIubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wNjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+NDUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzEubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wNzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTAubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wODkubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNDkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzcubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wNzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+ODIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dy53d3cxLndlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzkubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTgubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wMTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+MzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjIubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wNjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTIubm90
 LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wMzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTcubm90LXdlYi1w
+MByCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjQubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wMjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+MjIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTQubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzMubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTQubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+NDYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTcubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjAubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDEubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wMzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+OTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDIubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wNjcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzcubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDgubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTYubm90LXdlYi1w
 bGF0Zm9ybS50ZXN0MByCGm9wODQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-MzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTMubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTgubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0
-MByCGm9wMzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0MByCGm9wMzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
-ODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMzAubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0MByCGm9wNDUubm90LXdlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzIud3d3
-Mi53ZWItcGxhdGZvcm0udGVzdDAdght3d3cxLnd3dzEud2ViLXBsYXRmb3JtLnRl
-c3QwHYIbd3d3MS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzIud3d3MS53
+MzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNjkubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTMubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzEud3d3LndlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wODYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTMubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wMjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+NzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMjcubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNzUubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTgubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wNjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+Mjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNDMubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wNjYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGnd3dzIud3d3
+LndlYi1wbGF0Zm9ybS50ZXN0MByCGm9wOTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0
+MByCGm9wNzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wNTkubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0MByCGm9wODgubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9w
+ODcubm90LXdlYi1wbGF0Zm9ybS50ZXN0MByCGm9wMTAubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0MByCGm9wMTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3
+Mi53ZWItcGxhdGZvcm0udGVzdDAdght3d3cyLnd3dzIud2ViLXBsYXRmb3JtLnRl
+c3QwHYIbd3d3Mi53d3cxLndlYi1wbGF0Zm9ybS50ZXN0MB2CG3d3dzEud3d3MS53
 ZWItcGxhdGZvcm0udGVzdDAfgh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz
-dDAggh53d3cxLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3Lnd3dzEu
+dDAggh54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3MS53d3cu
 bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCCCHnd3dy53d3cyLm5vdC13ZWItcGxhdGZv
-cm0udGVzdDAggh53d3cyLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIeeG4t
-LWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3MS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3QwIYIfd3d3MS53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVz
-dDAhgh93d3cyLnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzEud3d3
+cm0udGVzdDAggh53d3cyLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwIIIed3d3
+Lnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzIud3d3Mi5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3QwIYIfd3d3Mi53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVz
+dDAhgh93d3cxLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCGCH3d3dzEud3d3
 Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwJIIieG4tLWx2ZS02bGFkLnd3dy53ZWIt
-cGxhdGZvcm0udGVzdDAkgiJ3d3cueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50
-ZXN0MCSCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4t
-LWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFk
-Lnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3Mi54bi0tbHZlLTZsYWQud2Vi
+cGxhdGZvcm0udGVzdDAkgiJ4bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0MCSCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwJYIjd3d3
+Mi54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFk
+Lnd3dzIud2ViLXBsYXRmb3JtLnRlc3QwJYIjeG4tLWx2ZS02bGFkLnd3dzEud2Vi
 LXBsYXRmb3JtLnRlc3QwJYIjd3d3MS54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3Jt
 LnRlc3QwKIImeG4tLWx2ZS02bGFkLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw
-KIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYInd3d3
-MS54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3huLS1sdmUt
-NmxhZC53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdDApgid4bi0tbHZlLTZsYWQu
-d3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYInd3d3Mi54bi0tbHZlLTZsYWQu
+KIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4t
+LWx2ZS02bGFkLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MCmCJ3d3dzIueG4t
+LWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDApgid3d3cxLnhuLS1sdmUt
+NmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwKYIneG4tLWx2ZS02bGFkLnd3dzIu
 bm90LXdlYi1wbGF0Zm9ybS50ZXN0MCuCKXhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
 LndlYi1wbGF0Zm9ybS50ZXN0MC2CK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQu
-d2ViLXBsYXRmb3JtLnRlc3QwL4IteG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3
+d2ViLXBsYXRmb3JtLnRlc3QwL4Itd3d3LnhuLS1uOGo2ZHM1M2x3d2tycWh2Mjhh
 LndlYi1wbGF0Zm9ybS50ZXN0MC+CLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLm5v
-dC13ZWItcGxhdGZvcm0udGVzdDAvgi13d3cueG4tLW44ajZkczUzbHd3a3JxaHYy
-OGEud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3Mi54bi0tbjhqNmRzNTNsd3drcnFo
-djI4YS53ZWItcGxhdGZvcm0udGVzdDAwgi53d3cxLnhuLS1uOGo2ZHM1M2x3d2ty
-cWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0MDCCLnhuLS1uOGo2ZHM1M2x3d2tycWh2
-MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwMIIueG4tLW44ajZkczUzbHd3a3Jx
-aHYyOGEud3d3Mi53ZWItcGxhdGZvcm0udGVzdDAxgi94bi0tbHZlLTZsYWQueG4t
+dC13ZWItcGxhdGZvcm0udGVzdDAvgi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS53
+d3cud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3MS54bi0tbjhqNmRzNTNsd3drcnFo
+djI4YS53ZWItcGxhdGZvcm0udGVzdDAwgi54bi0tbjhqNmRzNTNsd3drcnFodjI4
+YS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0MDCCLnhuLS1uOGo2ZHM1M2x3d2tycWh2
+MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3QwMIIud3d3Mi54bi0tbjhqNmRzNTNs
+d3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdDAxgi94bi0tbHZlLTZsYWQueG4t
 LWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdDAzgjF3d3cueG4tLW44ajZk
 czUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0MDOCMXhuLS1uOGo2
 ZHM1M2x3d2tycWh2MjhhLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwNIIyeG4t
-LW44ajZkczUzbHd3a3JxaHYyOGEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw
-NIIyd3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3QwNIIyd3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3QwNIIyeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qt
+LW44ajZkczUzbHd3a3JxaHYyOGEud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3Qw
+NIIyd3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3Jt
+LnRlc3QwNIIyd3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3QwNIIyeG4tLW44ajZkczUzbHd3a3JxaHYyOGEud3d3MS5ub3Qt
 d2ViLXBsYXRmb3JtLnRlc3QwOII2eG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4t
 LWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0MDiCNnhuLS1sdmUtNmxhZC54bi0t
 bjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdDA8gjp4bi0tbjhq
@@ -180,156 +180,156 @@
 LW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3QwR4JFeG4tLW44
 ajZkczUzbHd3a3JxaHYyOGEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdl
 Yi1wbGF0Zm9ybS50ZXN0MBMGA1UdJQQMMAoGCCsGAQUFBwMBMIIdjwYDVR0RBIId
-hjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-FW9wNi53ZWItcGxhdGZvcm0udGVzdIIVd3d3LndlYi1wbGF0Zm9ybS50ZXN0ghVv
-cDEud2ViLXBsYXRmb3JtLnRlc3SCFW9wNy53ZWItcGxhdGZvcm0udGVzdIIVb3A4
-LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDIud2ViLXBsYXRmb3JtLnRlc3SCFW9wOS53
-ZWItcGxhdGZvcm0udGVzdIIVb3A1LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDQud2Vi
-LXBsYXRmb3JtLnRlc3SCFW9wMy53ZWItcGxhdGZvcm0udGVzdIIWb3A0MC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A2MS53ZWItcGxhdGZvcm0udGVzdIIWb3AzMy53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A3OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzOC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A0My53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxhdGZvcm0udGVzdIIWb3AxNC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzNi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyMS53ZWItcGxhdGZvcm0udGVzdIIWb3A2MC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ni53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxhdGZvcm0udGVzdIIWb3AxOC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1Ny53ZWItcGxhdGZvcm0udGVzdIIWd3d3Mi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxhdGZvcm0udGVzdIIWb3A0MS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A1Mi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyNS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxhdGZvcm0udGVzdIIWb3AxMC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxhdGZvcm0udGVzdIIWb3AxMi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3NC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxhdGZvcm0udGVzdIIWb3A4NC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxhdGZvcm0udGVzdIIWb3A0NS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ni53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AzNC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0OC53ZWItcGxhdGZvcm0udGVzdIIWb3A3NS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxhdGZvcm0udGVzdIIWb3A3My53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdIIWb3A5Mi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AzMi53ZWItcGxhdGZvcm0udGVzdIIWb3A4Mi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ny53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2NC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A4NS53ZWItcGxhdGZvcm0udGVzdIIWb3A1OC53ZWIt
-cGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A4My53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxhdGZvcm0udGVzdIIWb3A2OC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzOS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxhdGZvcm0udGVzdIIWb3A5NS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1My53ZWItcGxhdGZvcm0udGVzdIIWb3A2My53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1NC53ZWItcGxhdGZvcm0udGVzdIIWb3A4OC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxhdGZvcm0udGVzdIIWb3AyOC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ni53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxhdGZvcm0udGVzdIIWb3A5MC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ny53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A2NS53ZWItcGxhdGZvcm0udGVzdIIWb3AyNy53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A3Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3Mi53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AyOS53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ny53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxhdGZvcm0udGVzdIIWb3A1NS53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A0Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3OC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxhdGZvcm0udGVzdIIWb3AyNC53ZWIt
-cGxhdGZvcm0udGVzdIIWb3A4MS53ZWItcGxhdGZvcm0udGVzdIIZb3A3Lm5vdC13
-ZWItcGxhdGZvcm0udGVzdIIZb3A0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A4
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWItcGxhdGZvcm0udGVz
-dIIZb3A5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIZb3AxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5vdC13ZWIt
-cGxhdGZvcm0udGVzdIIZb3A1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AyLm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3AyNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTQubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghpvcDc1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1NC5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wMjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI4
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk1Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A1My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzcubm90
+hjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVvcDgud2ViLXBsYXRmb3JtLnRlc3SC
+FW9wNy53ZWItcGxhdGZvcm0udGVzdIIVb3A5LndlYi1wbGF0Zm9ybS50ZXN0ghVv
+cDQud2ViLXBsYXRmb3JtLnRlc3SCFW5vdC13ZWItcGxhdGZvcm0udGVzdIIVb3A2
+LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDMud2ViLXBsYXRmb3JtLnRlc3SCFW9wMi53
+ZWItcGxhdGZvcm0udGVzdIIVb3AxLndlYi1wbGF0Zm9ybS50ZXN0ghV3d3cud2Vi
+LXBsYXRmb3JtLnRlc3SCFW9wNS53ZWItcGxhdGZvcm0udGVzdIIWb3A4OC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxhdGZvcm0udGVzdIIWb3A4NS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ni53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyNC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A0MS53ZWItcGxhdGZvcm0udGVzdIIWb3A3OS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxhdGZvcm0udGVzdIIWb3A1OS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdIIWb3A2MC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1OC53ZWItcGxhdGZvcm0udGVzdIIWb3AyOC53ZWIt
+cGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxhdGZvcm0udGVzdIIWb3A0MC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A3NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxhdGZvcm0udGVzdIIWb3A3My53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AxMi53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1NC53ZWItcGxhdGZvcm0udGVzdIIWb3A2My53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxhdGZvcm0udGVzdIIWb3A5NS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AxNi53ZWItcGxhdGZvcm0udGVzdIIWb3AzNi53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxhdGZvcm0udGVzdIIWb3AyOS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxhdGZvcm0udGVzdIIWb3A0NC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdIIWb3A4NC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzMi53ZWItcGxhdGZvcm0udGVzdIIWb3A2MS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxhdGZvcm0udGVzdIIWd3d3Mi53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A0My53ZWItcGxhdGZvcm0udGVzdIIWb3A3OC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ni53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A5OS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A4Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ni53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxhdGZvcm0udGVzdIIWb3A5MC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxhdGZvcm0udGVzdIIWb3AxMC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ny53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxhdGZvcm0udGVzdIIWb3A0NS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2OC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ny53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxhdGZvcm0udGVzdIIWb3A2Ny53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AxNS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxhdGZvcm0udGVzdIIWb3A3NS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A2NC53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ny53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ni53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A4Mi53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyNS53ZWItcGxhdGZvcm0udGVzdIIWb3AxMS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxhdGZvcm0udGVzdIIWb3AzOC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A4My53ZWItcGxhdGZvcm0udGVzdIIWb3A4MS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxhdGZvcm0udGVzdIIWb3AyMS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxhdGZvcm0udGVzdIIWb3A0Mi53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxhdGZvcm0udGVzdIIWb3A2NS53ZWIt
+cGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ny53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxhdGZvcm0udGVzdIIWb3A1My53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxhdGZvcm0udGVzdIIWb3A0OC53ZWIt
+cGxhdGZvcm0udGVzdIIWb3AzNC53ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5vdC13
+ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3Ay
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A1Lm5vdC13ZWItcGxhdGZvcm0udGVz
+dIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lnd3dy53ZWItcGxhdGZv
+cm0udGVzdIIZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A0Lm5vdC13ZWIt
+cGxhdGZvcm0udGVzdIIZb3A4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A5Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3AzNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTMubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDUwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyNC5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk1
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4My5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDczLm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3AxOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjEubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3A3MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzgubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDQwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyNS5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wNjUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cu
+d3d3Mi53ZWItcGxhdGZvcm0udGVzdIIab3A4MC5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wNTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY4Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3A0NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzEubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDcyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3A5MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODkubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDQ5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3Ny5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wNzkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgy
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Lnd3dzEud2ViLXBsYXRmb3JtLnRl
+c3SCGm9wMTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM5Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3A0NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3AxNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzAubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDYyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2MS5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wOTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI5
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5OC5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wNjQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI2Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3AyMi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTQubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3AzMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjMubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDU3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1NC5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wODUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ2
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5Ny5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYwLm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3A5Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTEubm90
 LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3A2OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODcubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghp3d3cxLnd3dy53ZWItcGxhdGZvcm0udGVzdIIab3A3MC5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wODMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDkx
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4MS5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wOTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ4Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A2NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzYubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIa
-b3AyNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzgubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghp3d3cud3d3MS53ZWItcGxhdGZvcm0udGVzdIIab3A3MS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wMTUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDcy
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2NS5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ5Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A1MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3A4Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTIubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4OS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wODYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUy
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMC5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wMjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYzLm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A0Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzQubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3AxMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTgubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghpvcDY2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3Mi5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wMzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM5
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3My5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU1Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A2OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTEubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3AxNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTAubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghp3d3cyLnd3dy53ZWItcGxhdGZvcm0udGVzdIIab3A2MS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgw
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5MC5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wNjcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQzLm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A1OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDQubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3AxOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzMubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghpvcDIyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4OC5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wNjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQw
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0Ni5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU2Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3AyOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzQubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
-b3A4NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzUubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0ghpvcDkzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3OS5ub3Qtd2Vi
-LXBsYXRmb3JtLnRlc3SCGm9wMTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU3
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AzNi5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM4Lm5vdC13ZWItcGxh
-dGZvcm0udGVzdIIab3A4NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzAubm90
-LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIb
-d3d3Mi53d3cyLndlYi1wbGF0Zm9ybS50ZXN0ght3d3cxLnd3dzEud2ViLXBsYXRm
-b3JtLnRlc3SCG3d3dzEud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIbd3d3Mi53d3cx
+b3AzNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTkubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDQyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2Ny5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ4
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1NS5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wNTYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDg0Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3AzNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjkubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDExLm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3A5My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzEud3d3LndlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDg2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxMy5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGm9wMjAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc2
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyNy5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc1Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3AxNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNDcubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIa
+b3A2My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjgubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0ghpvcDQzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2Ni5ub3Qtd2Vi
+LXBsYXRmb3JtLnRlc3SCGnd3dzIud3d3LndlYi1wbGF0Zm9ybS50ZXN0ghpvcDkx
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3NC5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCGm9wNTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDg4Lm5vdC13ZWItcGxh
+dGZvcm0udGVzdIIab3A4Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTAubm90
+LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIb
+d3d3MS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0ght3d3cyLnd3dzIud2ViLXBsYXRm
+b3JtLnRlc3SCG3d3dzIud3d3MS53ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cx
 LndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz
-dIIed3d3MS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3MS5ub3Qt
+dIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0gh53d3cxLnd3dy5ub3Qt
 d2ViLXBsYXRmb3JtLnRlc3SCHnd3dy53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVz
-dIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh54bi0tbHZlLTZsYWQu
-d2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3Mi5u
+dIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gh53d3cud3d3MS5ub3Qt
+d2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5u
 b3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3Mi5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3SCInd3dy54
-bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC5ub3Qt
-d2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUtNmxhZC53d3cxLndlYi1wbGF0Zm9y
-bS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIjd3d3
-Mi54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCI3d3dzEueG4tLWx2ZS02
+LnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2ViLXBsYXRmb3JtLnRlc3SCInhuLS1s
+dmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInd3dy54bi0tbHZlLTZsYWQu
+d2ViLXBsYXRmb3JtLnRlc3SCI3d3dzIueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9y
+bS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIjeG4t
+LWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCI3d3dzEueG4tLWx2ZS02
 bGFkLndlYi1wbGF0Zm9ybS50ZXN0giZ4bi0tbHZlLTZsYWQud3d3Lm5vdC13ZWIt
 cGxhdGZvcm0udGVzdIImd3d3LnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3SCJ3d3dzEueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIn
-eG4tLWx2ZS02bGFkLnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid4bi0tbHZl
-LTZsYWQud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3d3dzIueG4tLWx2ZS02
-bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYy
+LnRlc3SCJ3huLS1sdmUtNmxhZC53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIn
+d3d3Mi54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gid3d3cxLnhu
+LS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53
+d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIpeG4tLW44ajZkczUzbHd3a3JxaHYy
 OGEud2ViLXBsYXRmb3JtLnRlc3SCK3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQu
-d2ViLXBsYXRmb3JtLnRlc3SCLXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dy53
+d2ViLXBsYXRmb3JtLnRlc3SCLXd3dy54bi0tbjhqNmRzNTNsd3drcnFodjI4YS53
 ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0gi13d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
-LXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
+Yi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cud2Vi
 LXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
-LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2Vi
 LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzIud2Vi
+LXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnd3dzEud2Vi
+LXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2Vi
 LXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxhZC54bi0tbHZlLTZsYWQubm90LXdl
 Yi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90
 LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cu
 bm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53
-d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyd3d3Mi54bi0tbjhqNmRzNTNsd3dr
-cnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMnd3dzEueG4tLW44ajZkczUz
+d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIyd3d3MS54bi0tbjhqNmRzNTNsd3dr
+cnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCMnd3dzIueG4tLW44ajZkczUz
 bHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0tbjhqNmRzNTNs
-d3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdII2eG4tLW44ajZk
+d3drcnFodjI4YS53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdII2eG4tLW44ajZk
 czUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0gjZ4
 bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3Jt
 LnRlc3SCOnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1sdmUtNmxhZC5ub3Qt
@@ -337,11 +337,11 @@
 cnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCQXhuLS1uOGo2ZHM1M2x3d2ty
 cWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLndlYi1wbGF0Zm9ybS50ZXN0
 gkV4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54bi0tbjhqNmRzNTNsd3drcnFodjI4
-YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJKoZIhvcNAQELBQADggEBADVc8bl1
-d4P2NmDg9XR7Lf97e9v4JIQMfvBpKk9kiyRrMGKHpWlGetSipBL4MAR0yvrHUs7+
-61Bbzu0L5Tzd/gyD7ZG8nYHZCThjrWFMdxdltwO2FNmb3xs8lAS8pCOXEcXwY8bv
-y/ODP24UZvkBsizQ/cm4uOD70cdPZq+gKf103nUtPNIkq+NhbpzoNfzV/XYIG4Mb
-TxAngSBX9/swqkYkgojpSJX+BPr0lZ9iNh/JNCUnwX/HRDYdt0br+ytEf2U0RQ97
-ZUlyC264H2+g8Gnv4BRbfvktaS4PpVSE29tAHBL0cowmx7jXuie3n2O35SDxQkgz
-P57oA3Ezv83wshY=
+YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJKoZIhvcNAQELBQADggEBAHOGp2Ji
+xKvvqNucL2gpFBIpsT8abmKBLBm4LsSBGEFPy12fDztkWBVTEN/WiyHRL93PPnn2
+YFn3/jSuAgq0LkSx8VB/Xn2CZgY9+WzL4++GN6I6kYAuuvG4/P6iwwDCwX7y2coD
+D75E4WVVTjEsKG2vRiVWzccmg/BTmvXQJU8DSPhzPQtU/D8qHUIe/McHmEW9sxpG
+ktJSXqAe0VnvwPXhJ/scOiyJaXvC8mRjM50nUGny0n9Nywltm3oxOAVAZIahZa7g
+KMnRywojNqlkccXeHCjH1wXOhzuyQX+MvvBqq968ttIV/hbUXh+D/Su9M0qQclbA
+09vdXeld+rSxP8s=
 -----END CERTIFICATE-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key
index 7b5d9ff1..b69ed2a 100644
--- a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key
+++ b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.key
@@ -1,28 +1,28 @@
 -----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC0NvriO1g8i0L7
-kEIwIDMFeyOvfiHxY8SnFioFfxtIiaVde1lC4DZm8+nC5z4uJa/IFghDpsPh0Mx3
-X8fZ/MK/W8i28hVf8tecB1NGevxZGBeVxDDZt7rMAsPCkRxw03BH2udMIY+8v68K
-ErT0G7ryzO8R3UN57RZsA3vtDfkvjaLgAbedjb4A/ETqBk/e+s36587iBPvqxaAm
-wFWyqzacRI/agK6EoOkEps8AeJlhHiVzLevF/MQxAxmS9ZQ4aGBrMmhSZEfGSfsk
-4bTwFucFrlFmwaNayWBlhrC677pqFZpWJYw5JBY+J+eYE8RiOCQfacD/XkQIktUy
-Djrq7GQrAgMBAAECggEBAIwW5SXx3eCKnRIzDNCeZysOkyn7keU0mg0M1LObIBle
-LrchiLzM0F1tpDzHR3XWA/Q09E2qmEC08Ayn3xJcQwNAFSHpw6Xnf6WhqCF0vy9+
-4+6fKR5FjabDS2u3I/Ws1250AzMSL8sY8reQ3SuZVtUha4Jmjup7298xQid/okJM
-uOemXHg/jBhwoYW8pWG331ezGTOxQExIVE3FTtlwSk5wkDbf7+klT4adwpEDRwpW
-JbI/xdq+r7SxGRKA5DNWETePQNQSKEzRXeZ+eh/ipWoNG6mXrppLs0EeaF55XB1b
-e1UvNFOCozsiTY2s8DBEg9hlqL+k7nLeaUGUtui5/EECgYEA2ST2jpNJfXcI9oPl
-yjg88cbBpaMGp3w1ygQzfnVQ2h05drM6frLqg/1MlpHW5XWxadeNn3PzlnBb6JVo
-v522Y/IRcSNLC8enfUTy/Oltem7RTggL4hMMi2yZordJ5AMvWqYCw22SNSMt3m9Z
-K4UnbkFpIDYJtetfPeNSkKm1e6ECgYEA1HZUfWwdJUc1mgOBSIzZ9v/SPRdIjz9E
-p3JqNIaJaXO/bE91Y1C0L26hX7gNmEtBjsHvQskOUSrDNkyCMGANRepyH3FfrF6V
-kuKUK3bSUkUNowL0ztzsk7QE/dRIg8gpLHQzHj9JTdz5qRSoDjJm2ph2rigRmJ9V
-2d59O04RrEsCgYEAxTA13n+OSytfrk1UzXCIl57Al6QWFN5NEmkCQiJTC99iIZLc
-2dWr9bR+anWByto4BD/E0jo/yCu8qteTSf70dIqMoEtGiSoDxVRpvJZV3srns47H
-C8P0rmAunH8J0M+7nvwGomXMUgjiTI6dUVIX3p3z01Z/Nv7JfLAEeG5E6kECgYBm
-iXk7Uss6K4TOALULW5byIwLHIw6Mu78ZhRmGogt9TjRrRGnl9ZQQdDcDqCM/hcps
-6GHdfIUhXR77fK80Q5cEUCKl1CSVXsyXKCzUUTMuK09qhcm6cFro6e+ixSn+F8Lv
-RmFJTsfFAUmodWSp/V8wTnawlHvxiax4Sm1sCsBywwKBgCL3fpUb8bMddwm7dgIT
-DWBVdjTbEvvZhJ4Ec0sSTxv3AwUoD70evuphotIucruLPhG0NWrPIQgZfjTKaZ24
-MBjMSWSfu+FH3J+UYaaFQKWp7fu65ioaNIrb/AhlCP68yl30m0vLGrDiZk66XAUx
-JPGxuQ/gxnR2RogWiLK9tQ+k
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcwhdziEv2WAkv
+K/wpecn5LRAprbWRjaotacXvktoxS0aK2ff34wiV7GrBucxxU81i3LCucnd82dGT
+4vHfzTKKab5/+vut1FNoG5BKmGYZCpOo6MZOWAJJ4zXYQBAEeKurSjglzOXWmjSp
+AEzM9TqUG66lpoSK58zv7gneDbjDnJhbKYZQurNOm3PLMd0ep3/yxqwqVia1nOn+
+xa4ZoFrWwguWDKx09yhBKEVDHXtAGfZp9EWATquEsqFSoeLqyQDvfe5Hefi4dPmY
+32OiJG4ArSKegxyRekQZ8E4x3mnlt3prC6nZFexLG60UOix/AN3RifpHDey8Zq/L
+pGsy+NT7AgMBAAECggEBAJrkOA4hAKNs66zEYN49DKCfpKqJrk7dJh1NDMtmr19M
+4McF3r1394sx4Unh8ndFhGMsU29i80GPl0P7RRhxYlfJkBc94574zjjKtjgQq/o/
++JDYGmPXzmtHV31Ona51eIXrwm+LT2x+sBowErLwEVTgA29I4dCQibOCwjuiRxQ/
+mn2A4Q60OllIRCwSE3/uA9+mUpeMp5jgJd+oN3uT58Tme/SRNXxOKgCie8WRUnue
+X/cghKYSNmAyDSkbJ0KY4oavb5YRKXNpAt2hNW9JsN0qd3+j6JZ21odhydDbtqSq
+mxjPTUFQNFeLVvDTaRYw+zK+I/noZIrlQsS6JPNfXkECgYEA+m3L9jLe2lz0SJmG
+NnFuY8rwwYVJm4TLhjYDmdmYbGcYCPo9CHHKhR6ZXrmNzxcXvwaZk8ZTspAZ2Bzw
+1AM52mhGZejR7yV5FECh+UKrx/Aud+jm0WhPtwYjixz8IhmGG81orYueux50HUcO
+Q/K5Nqo1esBBC+X5Ya2rb3jShGECgYEA4atRn6P5DCj4ug3SSlUNIS3dJxbe3QhB
+lTkCtXUQC+p+VIUI0mVk6NgN4drgViKOlhzMKYDMtiVY2XLXQNVPEJ4ngMSC1uzr
+tGefMuL/WRpsysxwjN0b+0fDVeXtM16CtXOpqnoYi3XX/R6aIqZ3zVi/ttwEOy6G
+TdgnZNcJVtsCgYAW70tIpuwF75FnvLev8L99YC6gaoaNOaIyDmxSAL2W3/IxkEla
+pqE3g8/j/vZfyuuf0QjrobQ0nEHhqvTbVdhMilQ4LRRc5H+sPScYXuTAkNyQmsHY
+18bFKkjDCsqEjPXdQfiePDUzSdy0ebdyvZ38xaXUMhtC7bLjITacJOKSwQKBgGlJ
+1kZmab8rqoicBD5cGkkdre4b9JUp0fd+Zu4klP0KRjDG9Qu89OzSSP/UcBCgBOiy
+vOqsRlbBbAfgVd/Q5he5wnKIvQbr+Tjtk9BZKov3EUU5R1Xhn7mIjPGZ2ia6dL+W
+HFYGq0b+D2zwhzeddY3gV2pIkszN8ymErTSWQ6w7AoGBAIECBMwE3YL0TGWPdU9A
+RV3a5G9slunqhVGQCwvBfWwj6tIplhtOLAp4y400DHbw4Jwi5Z+hDQu9PzMGhhwu
+qZLMJZJ4BAUaVHoEcuo1sab25UH6a0pdGf7BgCmjKjPAHtvzMyfwfKpju7ZObpqx
+Yet1DMpvmPlX1kZsEh072zBs
 -----END PRIVATE KEY-----
diff --git a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem
index 9f0929ad..e79323d 100644
--- a/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem
+++ b/third_party/wpt_tools/wpt/tools/certs/web-platform.test.pem
@@ -1,228 +1,228 @@
 Certificate:
     Data:
         Version: 3 (0x2)
-        Serial Number: 978030 (0xeec6e)
+        Serial Number: 415046 (0x65546)
         Signature Algorithm: sha256WithRSAEncryption
         Issuer: CN=web-platform-tests
         Validity
-            Not Before: Mar 12 00:27:34 2021 GMT
-            Not After : Mar 12 00:27:34 2022 GMT
+            Not Before: Jan 12 16:13:28 2021 GMT
+            Not After : Jan 12 16:13:28 2022 GMT
         Subject: CN=web-platform.test
         Subject Public Key Info:
             Public Key Algorithm: rsaEncryption
                 RSA Public-Key: (2048 bit)
                 Modulus:
-                    00:b4:36:fa:e2:3b:58:3c:8b:42:fb:90:42:30:20:
-                    33:05:7b:23:af:7e:21:f1:63:c4:a7:16:2a:05:7f:
-                    1b:48:89:a5:5d:7b:59:42:e0:36:66:f3:e9:c2:e7:
-                    3e:2e:25:af:c8:16:08:43:a6:c3:e1:d0:cc:77:5f:
-                    c7:d9:fc:c2:bf:5b:c8:b6:f2:15:5f:f2:d7:9c:07:
-                    53:46:7a:fc:59:18:17:95:c4:30:d9:b7:ba:cc:02:
-                    c3:c2:91:1c:70:d3:70:47:da:e7:4c:21:8f:bc:bf:
-                    af:0a:12:b4:f4:1b:ba:f2:cc:ef:11:dd:43:79:ed:
-                    16:6c:03:7b:ed:0d:f9:2f:8d:a2:e0:01:b7:9d:8d:
-                    be:00:fc:44:ea:06:4f:de:fa:cd:fa:e7:ce:e2:04:
-                    fb:ea:c5:a0:26:c0:55:b2:ab:36:9c:44:8f:da:80:
-                    ae:84:a0:e9:04:a6:cf:00:78:99:61:1e:25:73:2d:
-                    eb:c5:fc:c4:31:03:19:92:f5:94:38:68:60:6b:32:
-                    68:52:64:47:c6:49:fb:24:e1:b4:f0:16:e7:05:ae:
-                    51:66:c1:a3:5a:c9:60:65:86:b0:ba:ef:ba:6a:15:
-                    9a:56:25:8c:39:24:16:3e:27:e7:98:13:c4:62:38:
-                    24:1f:69:c0:ff:5e:44:08:92:d5:32:0e:3a:ea:ec:
-                    64:2b
+                    00:dc:c2:17:73:88:4b:f6:58:09:2f:2b:fc:29:79:
+                    c9:f9:2d:10:29:ad:b5:91:8d:aa:2d:69:c5:ef:92:
+                    da:31:4b:46:8a:d9:f7:f7:e3:08:95:ec:6a:c1:b9:
+                    cc:71:53:cd:62:dc:b0:ae:72:77:7c:d9:d1:93:e2:
+                    f1:df:cd:32:8a:69:be:7f:fa:fb:ad:d4:53:68:1b:
+                    90:4a:98:66:19:0a:93:a8:e8:c6:4e:58:02:49:e3:
+                    35:d8:40:10:04:78:ab:ab:4a:38:25:cc:e5:d6:9a:
+                    34:a9:00:4c:cc:f5:3a:94:1b:ae:a5:a6:84:8a:e7:
+                    cc:ef:ee:09:de:0d:b8:c3:9c:98:5b:29:86:50:ba:
+                    b3:4e:9b:73:cb:31:dd:1e:a7:7f:f2:c6:ac:2a:56:
+                    26:b5:9c:e9:fe:c5:ae:19:a0:5a:d6:c2:0b:96:0c:
+                    ac:74:f7:28:41:28:45:43:1d:7b:40:19:f6:69:f4:
+                    45:80:4e:ab:84:b2:a1:52:a1:e2:ea:c9:00:ef:7d:
+                    ee:47:79:f8:b8:74:f9:98:df:63:a2:24:6e:00:ad:
+                    22:9e:83:1c:91:7a:44:19:f0:4e:31:de:69:e5:b7:
+                    7a:6b:0b:a9:d9:15:ec:4b:1b:ad:14:3a:2c:7f:00:
+                    dd:d1:89:fa:47:0d:ec:bc:66:af:cb:a4:6b:32:f8:
+                    d4:fb
                 Exponent: 65537 (0x10001)
         X509v3 extensions:
             X509v3 Basic Constraints: 
                 CA:FALSE
             X509v3 Subject Key Identifier: 
-                C9:06:D2:C5:1F:09:F4:48:6A:0F:40:E8:29:4B:33:22:A0:8A:FB:33
+                CD:F1:C8:62:D1:EC:A5:3D:E4:1A:91:70:F1:02:E6:6E:BC:2F:E2:05
             X509v3 Authority Key Identifier: 
-                keyid:BD:78:38:C2:37:F3:9C:06:A8:EB:3E:AF:5A:A1:88:24:14:85:5B:BE
+                keyid:DC:6D:8D:62:DD:54:98:C8:60:17:C2:D3:51:B3:BF:73:5B:5C:90:B9
 
             X509v3 Key Usage: 
                 Digital Signature, Non Repudiation, Key Encipherment
             X509v3 Extended Key Usage: 
                 TLS Web Server Authentication
             X509v3 Subject Alternative Name: 
-                DNS:web-platform.test, DNS:not-web-platform.test, DNS:op6.web-platform.test, DNS:www.web-platform.test, DNS:op1.web-platform.test, DNS:op7.web-platform.test, DNS:op8.web-platform.test, DNS:op2.web-platform.test, DNS:op9.web-platform.test, DNS:op5.web-platform.test, DNS:op4.web-platform.test, DNS:op3.web-platform.test, DNS:op40.web-platform.test, DNS:op61.web-platform.test, DNS:op33.web-platform.test, DNS:op79.web-platform.test, DNS:op38.web-platform.test, DNS:op77.web-platform.test, DNS:op43.web-platform.test, DNS:op44.web-platform.test, DNS:op14.web-platform.test, DNS:op49.web-platform.test, DNS:op36.web-platform.test, DNS:op21.web-platform.test, DNS:op60.web-platform.test, DNS:op71.web-platform.test, DNS:op56.web-platform.test, DNS:op94.web-platform.test, DNS:op18.web-platform.test, DNS:op57.web-platform.test, DNS:www2.web-platform.test, DNS:op91.web-platform.test, DNS:op41.web-platform.test, DNS:op47.web-platform.test, DNS:op52.web-platform.test, DNS:op25.web-platform.test, DNS:op16.web-platform.test, DNS:op26.web-platform.test, DNS:op10.web-platform.test, DNS:op69.web-platform.test, DNS:op12.web-platform.test, DNS:op96.web-platform.test, DNS:op74.web-platform.test, DNS:op89.web-platform.test, DNS:op84.web-platform.test, DNS:op37.web-platform.test, DNS:op45.web-platform.test, DNS:op62.web-platform.test, DNS:op86.web-platform.test, DNS:op42.web-platform.test, DNS:op34.web-platform.test, DNS:op48.web-platform.test, DNS:op75.web-platform.test, DNS:op50.web-platform.test, DNS:op22.web-platform.test, DNS:op23.web-platform.test, DNS:op73.web-platform.test, DNS:op20.web-platform.test, DNS:op92.web-platform.test, DNS:op32.web-platform.test, DNS:op82.web-platform.test, DNS:op98.web-platform.test, DNS:op31.web-platform.test, DNS:op30.web-platform.test, DNS:op87.web-platform.test, DNS:op70.web-platform.test, DNS:op64.web-platform.test, DNS:op11.web-platform.test, DNS:op15.web-platform.test, DNS:op85.web-platform.test, DNS:op58.web-platform.test, DNS:www1.web-platform.test, DNS:op83.web-platform.test, DNS:op13.web-platform.test, DNS:op68.web-platform.test, DNS:op99.web-platform.test, DNS:op39.web-platform.test, DNS:op59.web-platform.test, DNS:op95.web-platform.test, DNS:op53.web-platform.test, DNS:op63.web-platform.test, DNS:op54.web-platform.test, DNS:op88.web-platform.test, DNS:op93.web-platform.test, DNS:op28.web-platform.test, DNS:op51.web-platform.test, DNS:op66.web-platform.test, DNS:op19.web-platform.test, DNS:op90.web-platform.test, DNS:op80.web-platform.test, DNS:op67.web-platform.test, DNS:op65.web-platform.test, DNS:op27.web-platform.test, DNS:op76.web-platform.test, DNS:op72.web-platform.test, DNS:op29.web-platform.test, DNS:op97.web-platform.test, DNS:op35.web-platform.test, DNS:op55.web-platform.test, DNS:op46.web-platform.test, DNS:op78.web-platform.test, DNS:op17.web-platform.test, DNS:op24.web-platform.test, DNS:op81.web-platform.test, DNS:op7.not-web-platform.test, DNS:op4.not-web-platform.test, DNS:op8.not-web-platform.test, DNS:www.www.web-platform.test, DNS:op9.not-web-platform.test, DNS:www.not-web-platform.test, DNS:op1.not-web-platform.test, DNS:op3.not-web-platform.test, DNS:op5.not-web-platform.test, DNS:op2.not-web-platform.test, DNS:op6.not-web-platform.test, DNS:op26.not-web-platform.test, DNS:op94.not-web-platform.test, DNS:op75.not-web-platform.test, DNS:op54.not-web-platform.test, DNS:op25.not-web-platform.test, DNS:op28.not-web-platform.test, DNS:op92.not-web-platform.test, DNS:op17.not-web-platform.test, DNS:op95.not-web-platform.test, DNS:op53.not-web-platform.test, DNS:op37.not-web-platform.test, DNS:op41.not-web-platform.test, DNS:op68.not-web-platform.test, DNS:op87.not-web-platform.test, DNS:www1.www.web-platform.test, DNS:op70.not-web-platform.test, DNS:op83.not-web-platform.test, DNS:op91.not-web-platform.test, DNS:op81.not-web-platform.test, DNS:op99.not-web-platform.test, DNS:op48.not-web-platform.test, DNS:op64.not-web-platform.test, DNS:op76.not-web-platform.test, DNS:www.www2.web-platform.test, DNS:op24.not-web-platform.test, DNS:op78.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:op71.not-web-platform.test, DNS:op15.not-web-platform.test, DNS:op72.not-web-platform.test, DNS:op65.not-web-platform.test, DNS:op98.not-web-platform.test, DNS:op49.not-web-platform.test, DNS:op50.not-web-platform.test, DNS:www1.not-web-platform.test, DNS:op47.not-web-platform.test, DNS:op82.not-web-platform.test, DNS:op12.not-web-platform.test, DNS:op27.not-web-platform.test, DNS:op89.not-web-platform.test, DNS:op86.not-web-platform.test, DNS:op52.not-web-platform.test, DNS:op20.not-web-platform.test, DNS:op23.not-web-platform.test, DNS:op63.not-web-platform.test, DNS:op42.not-web-platform.test, DNS:op74.not-web-platform.test, DNS:op62.not-web-platform.test, DNS:op13.not-web-platform.test, DNS:op58.not-web-platform.test, DNS:op66.not-web-platform.test, DNS:www2.not-web-platform.test, DNS:op31.not-web-platform.test, DNS:op39.not-web-platform.test, DNS:op73.not-web-platform.test, DNS:op77.not-web-platform.test, DNS:op55.not-web-platform.test, DNS:op69.not-web-platform.test, DNS:op51.not-web-platform.test, DNS:op96.not-web-platform.test, DNS:op16.not-web-platform.test, DNS:op10.not-web-platform.test, DNS:www2.www.web-platform.test, DNS:op61.not-web-platform.test, DNS:op21.not-web-platform.test, DNS:op80.not-web-platform.test, DNS:op90.not-web-platform.test, DNS:op67.not-web-platform.test, DNS:op43.not-web-platform.test, DNS:op59.not-web-platform.test, DNS:op44.not-web-platform.test, DNS:op14.not-web-platform.test, DNS:op19.not-web-platform.test, DNS:op33.not-web-platform.test, DNS:op22.not-web-platform.test, DNS:op88.not-web-platform.test, DNS:op60.not-web-platform.test, DNS:op40.not-web-platform.test, DNS:op46.not-web-platform.test, DNS:op32.not-web-platform.test, DNS:op56.not-web-platform.test, DNS:op29.not-web-platform.test, DNS:op34.not-web-platform.test, DNS:op97.not-web-platform.test, DNS:op84.not-web-platform.test, DNS:op35.not-web-platform.test, DNS:op93.not-web-platform.test, DNS:op79.not-web-platform.test, DNS:op18.not-web-platform.test, DNS:op57.not-web-platform.test, DNS:op36.not-web-platform.test, DNS:op11.not-web-platform.test, DNS:op38.not-web-platform.test, DNS:op85.not-web-platform.test, DNS:op30.not-web-platform.test, DNS:op45.not-web-platform.test, DNS:www2.www2.web-platform.test, DNS:www1.www1.web-platform.test, DNS:www1.www2.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www.www.not-web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www.www1.not-web-platform.test, DNS:www.www2.not-web-platform.test, DNS:www2.www.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test
+                DNS:web-platform.test, DNS:op8.web-platform.test, DNS:op7.web-platform.test, DNS:op9.web-platform.test, DNS:op4.web-platform.test, DNS:not-web-platform.test, DNS:op6.web-platform.test, DNS:op3.web-platform.test, DNS:op2.web-platform.test, DNS:op1.web-platform.test, DNS:www.web-platform.test, DNS:op5.web-platform.test, DNS:op88.web-platform.test, DNS:op98.web-platform.test, DNS:op85.web-platform.test, DNS:op89.web-platform.test, DNS:op66.web-platform.test, DNS:op72.web-platform.test, DNS:op24.web-platform.test, DNS:op41.web-platform.test, DNS:op79.web-platform.test, DNS:op91.web-platform.test, DNS:op59.web-platform.test, DNS:op39.web-platform.test, DNS:op60.web-platform.test, DNS:op58.web-platform.test, DNS:op28.web-platform.test, DNS:www1.web-platform.test, DNS:op14.web-platform.test, DNS:op69.web-platform.test, DNS:op40.web-platform.test, DNS:op74.web-platform.test, DNS:op31.web-platform.test, DNS:op18.web-platform.test, DNS:op73.web-platform.test, DNS:op77.web-platform.test, DNS:op12.web-platform.test, DNS:op54.web-platform.test, DNS:op63.web-platform.test, DNS:op71.web-platform.test, DNS:op95.web-platform.test, DNS:op16.web-platform.test, DNS:op36.web-platform.test, DNS:op27.web-platform.test, DNS:op29.web-platform.test, DNS:op94.web-platform.test, DNS:op44.web-platform.test, DNS:op33.web-platform.test, DNS:op84.web-platform.test, DNS:op32.web-platform.test, DNS:op61.web-platform.test, DNS:op70.web-platform.test, DNS:www2.web-platform.test, DNS:op43.web-platform.test, DNS:op78.web-platform.test, DNS:op26.web-platform.test, DNS:op76.web-platform.test, DNS:op52.web-platform.test, DNS:op99.web-platform.test, DNS:op86.web-platform.test, DNS:op46.web-platform.test, DNS:op17.web-platform.test, DNS:op90.web-platform.test, DNS:op93.web-platform.test, DNS:op10.web-platform.test, DNS:op55.web-platform.test, DNS:op47.web-platform.test, DNS:op51.web-platform.test, DNS:op45.web-platform.test, DNS:op80.web-platform.test, DNS:op68.web-platform.test, DNS:op49.web-platform.test, DNS:op57.web-platform.test, DNS:op35.web-platform.test, DNS:op67.web-platform.test, DNS:op92.web-platform.test, DNS:op15.web-platform.test, DNS:op13.web-platform.test, DNS:op75.web-platform.test, DNS:op64.web-platform.test, DNS:op97.web-platform.test, DNS:op37.web-platform.test, DNS:op56.web-platform.test, DNS:op62.web-platform.test, DNS:op82.web-platform.test, DNS:op25.web-platform.test, DNS:op11.web-platform.test, DNS:op50.web-platform.test, DNS:op38.web-platform.test, DNS:op83.web-platform.test, DNS:op81.web-platform.test, DNS:op20.web-platform.test, DNS:op21.web-platform.test, DNS:op23.web-platform.test, DNS:op42.web-platform.test, DNS:op22.web-platform.test, DNS:op65.web-platform.test, DNS:op96.web-platform.test, DNS:op87.web-platform.test, DNS:op19.web-platform.test, DNS:op53.web-platform.test, DNS:op30.web-platform.test, DNS:op48.web-platform.test, DNS:op34.web-platform.test, DNS:op6.not-web-platform.test, DNS:op3.not-web-platform.test, DNS:op2.not-web-platform.test, DNS:op5.not-web-platform.test, DNS:www.not-web-platform.test, DNS:www.www.web-platform.test, DNS:op7.not-web-platform.test, DNS:op4.not-web-platform.test, DNS:op8.not-web-platform.test, DNS:op9.not-web-platform.test, DNS:op1.not-web-platform.test, DNS:op36.not-web-platform.test, DNS:op53.not-web-platform.test, DNS:op50.not-web-platform.test, DNS:op24.not-web-platform.test, DNS:op31.not-web-platform.test, DNS:op95.not-web-platform.test, DNS:op83.not-web-platform.test, DNS:www2.not-web-platform.test, DNS:op73.not-web-platform.test, DNS:op19.not-web-platform.test, DNS:op21.not-web-platform.test, DNS:op81.not-web-platform.test, DNS:op70.not-web-platform.test, DNS:op78.not-web-platform.test, DNS:op40.not-web-platform.test, DNS:op25.not-web-platform.test, DNS:op65.not-web-platform.test, DNS:www.www2.web-platform.test, DNS:op80.not-web-platform.test, DNS:op52.not-web-platform.test, DNS:op68.not-web-platform.test, DNS:op45.not-web-platform.test, DNS:op71.not-web-platform.test, DNS:op72.not-web-platform.test, DNS:op90.not-web-platform.test, DNS:op89.not-web-platform.test, DNS:op49.not-web-platform.test, DNS:op77.not-web-platform.test, DNS:op79.not-web-platform.test, DNS:op82.not-web-platform.test, DNS:www.www1.web-platform.test, DNS:op12.not-web-platform.test, DNS:op39.not-web-platform.test, DNS:op44.not-web-platform.test, DNS:www1.not-web-platform.test, DNS:op58.not-web-platform.test, DNS:op14.not-web-platform.test, DNS:op30.not-web-platform.test, DNS:op62.not-web-platform.test, DNS:op61.not-web-platform.test, DNS:op92.not-web-platform.test, DNS:op29.not-web-platform.test, DNS:op98.not-web-platform.test, DNS:op64.not-web-platform.test, DNS:op26.not-web-platform.test, DNS:op22.not-web-platform.test, DNS:op94.not-web-platform.test, DNS:op38.not-web-platform.test, DNS:op33.not-web-platform.test, DNS:op23.not-web-platform.test, DNS:op57.not-web-platform.test, DNS:op54.not-web-platform.test, DNS:op85.not-web-platform.test, DNS:op46.not-web-platform.test, DNS:op97.not-web-platform.test, DNS:op32.not-web-platform.test, DNS:op60.not-web-platform.test, DNS:op96.not-web-platform.test, DNS:op51.not-web-platform.test, DNS:op41.not-web-platform.test, DNS:op35.not-web-platform.test, DNS:op99.not-web-platform.test, DNS:op42.not-web-platform.test, DNS:op67.not-web-platform.test, DNS:op37.not-web-platform.test, DNS:op48.not-web-platform.test, DNS:op55.not-web-platform.test, DNS:op56.not-web-platform.test, DNS:op84.not-web-platform.test, DNS:op34.not-web-platform.test, DNS:op69.not-web-platform.test, DNS:op11.not-web-platform.test, DNS:op93.not-web-platform.test, DNS:www1.www.web-platform.test, DNS:op86.not-web-platform.test, DNS:op13.not-web-platform.test, DNS:op20.not-web-platform.test, DNS:op76.not-web-platform.test, DNS:op27.not-web-platform.test, DNS:op17.not-web-platform.test, DNS:op75.not-web-platform.test, DNS:op15.not-web-platform.test, DNS:op47.not-web-platform.test, DNS:op18.not-web-platform.test, DNS:op63.not-web-platform.test, DNS:op28.not-web-platform.test, DNS:op43.not-web-platform.test, DNS:op66.not-web-platform.test, DNS:www2.www.web-platform.test, DNS:op91.not-web-platform.test, DNS:op74.not-web-platform.test, DNS:op59.not-web-platform.test, DNS:op88.not-web-platform.test, DNS:op87.not-web-platform.test, DNS:op10.not-web-platform.test, DNS:op16.not-web-platform.test, DNS:www1.www2.web-platform.test, DNS:www2.www2.web-platform.test, DNS:www2.www1.web-platform.test, DNS:www1.www1.web-platform.test, DNS:www.www.not-web-platform.test, DNS:xn--lve-6lad.web-platform.test, DNS:www1.www.not-web-platform.test, DNS:www.www2.not-web-platform.test, DNS:www2.www.not-web-platform.test, DNS:www.www1.not-web-platform.test, DNS:www2.www2.not-web-platform.test, DNS:www2.www1.not-web-platform.test, DNS:www1.www1.not-web-platform.test, DNS:www1.www2.not-web-platform.test, DNS:xn--lve-6lad.www.web-platform.test, DNS:xn--lve-6lad.not-web-platform.test, DNS:www.xn--lve-6lad.web-platform.test, DNS:www2.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www2.web-platform.test, DNS:xn--lve-6lad.www1.web-platform.test, DNS:www1.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.www.not-web-platform.test, DNS:www.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www1.not-web-platform.test, DNS:www2.xn--lve-6lad.not-web-platform.test, DNS:www1.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.www2.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--lve-6lad.xn--lve-6lad.not-web-platform.test, DNS:www.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www2.not-web-platform.test, DNS:www1.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:www2.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.www1.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--lve-6lad.not-web-platform.test, DNS:xn--lve-6lad.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.web-platform.test, DNS:xn--n8j6ds53lwwkrqhv28a.xn--n8j6ds53lwwkrqhv28a.not-web-platform.test
     Signature Algorithm: sha256WithRSAEncryption
-         20:ff:20:71:e5:2d:9f:16:4a:f0:b8:ef:cb:23:63:56:70:bc:
-         8c:c6:6b:0e:fa:f5:80:55:5a:f5:75:58:cd:c6:7e:66:6d:11:
-         33:ef:fc:a6:6b:5b:98:04:d5:6b:5b:ee:8d:3c:0b:13:d4:f9:
-         6b:6e:9b:b5:ad:a6:6e:05:d4:d3:f5:ff:b1:a7:17:46:8e:98:
-         7b:89:87:14:a4:c1:fa:26:02:6d:44:c5:c8:c6:5a:d2:9c:e8:
-         32:83:ab:77:07:80:c8:80:ab:1f:c6:56:7a:ee:7f:aa:1d:6b:
-         37:e1:d5:c1:04:54:e5:30:41:e9:a5:9e:f0:7d:8f:f5:24:60:
-         f0:24:79:cb:d2:e8:2d:95:33:9d:ca:98:02:11:37:47:97:43:
-         13:c2:8a:73:a3:e1:14:cb:86:de:70:c2:b1:d5:5b:d9:6d:f6:
-         ad:6f:cc:a5:2b:9b:21:8b:d7:78:03:5c:2b:e4:f8:42:c5:7d:
-         0d:07:b0:e1:41:ed:ac:26:95:93:db:12:9b:a3:6e:ff:90:62:
-         0d:10:ae:d5:f4:87:3d:3a:50:55:c7:c4:e0:48:53:91:e9:22:
-         eb:97:a6:31:42:2b:3f:24:06:12:5c:92:ff:69:5e:af:00:fd:
-         e6:ec:2d:66:30:7f:59:db:d1:6f:bc:2d:f4:8b:d3:74:25:e1:
-         a5:46:79:2d
+         38:a7:ef:eb:55:30:e8:6f:bf:51:a9:eb:52:9a:66:ec:3d:19:
+         5d:f4:1d:84:17:c0:f2:26:3e:2b:66:5d:7a:a9:44:86:c3:ba:
+         d7:f0:9e:e7:b2:b3:05:0c:25:ef:e1:b7:94:8c:44:1c:d2:57:
+         4c:30:51:96:29:96:2e:b3:e3:1c:f8:9c:e6:7d:96:14:3f:3f:
+         3e:a6:96:4b:01:dc:f2:ed:bf:fc:e3:64:93:49:81:be:c9:dd:
+         dd:1b:ce:da:72:45:d1:2d:ca:99:cd:d1:7d:f9:17:e1:ee:12:
+         f4:ed:76:41:ca:6f:a5:5c:72:00:4a:8d:76:c5:2b:b7:18:7b:
+         ce:e8:ab:76:9a:75:e9:1d:53:9b:75:93:6d:0b:2e:49:3f:bf:
+         84:1f:71:be:49:23:ab:2c:f8:a6:a2:28:93:82:04:6c:8e:85:
+         22:0e:b6:6d:c5:1e:82:d1:0d:c6:08:9a:86:a1:29:5c:79:53:
+         d3:ae:d6:c4:33:4b:d2:04:5a:d9:a0:c3:6d:26:ec:e8:35:06:
+         e7:88:12:03:7c:c5:83:26:b2:b5:32:a3:41:51:b4:94:b0:84:
+         0d:4a:05:52:02:29:41:5b:03:04:f0:c3:e5:24:e6:5a:ef:70:
+         45:45:58:25:2b:5e:be:7d:ca:73:02:2b:1d:4f:3c:4b:00:f4:
+         69:5f:1a:6e
 -----BEGIN CERTIFICATE-----
-MIIgvDCCH6SgAwIBAgIDDuxuMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
-Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTAzMTIwMDI3MzRaFw0yMjAzMTIwMDI3MzRa
+MIIgvDCCH6SgAwIBAgIDBlVGMA0GCSqGSIb3DQEBCwUAMB0xGzAZBgNVBAMMEndl
+Yi1wbGF0Zm9ybS10ZXN0czAeFw0yMTAxMTIxNjEzMjhaFw0yMjAxMTIxNjEzMjha
 MBwxGjAYBgNVBAMMEXdlYi1wbGF0Zm9ybS50ZXN0MIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAtDb64jtYPItC+5BCMCAzBXsjr34h8WPEpxYqBX8bSIml
-XXtZQuA2ZvPpwuc+LiWvyBYIQ6bD4dDMd1/H2fzCv1vItvIVX/LXnAdTRnr8WRgX
-lcQw2be6zALDwpEccNNwR9rnTCGPvL+vChK09Bu68szvEd1Dee0WbAN77Q35L42i
-4AG3nY2+APxE6gZP3vrN+ufO4gT76sWgJsBVsqs2nESP2oCuhKDpBKbPAHiZYR4l
-cy3rxfzEMQMZkvWUOGhgazJoUmRHxkn7JOG08BbnBa5RZsGjWslgZYawuu+6ahWa
-ViWMOSQWPifnmBPEYjgkH2nA/15ECJLVMg466uxkKwIDAQABo4IeBDCCHgAwCQYD
-VR0TBAIwADAdBgNVHQ4EFgQUyQbSxR8J9EhqD0DoKUszIqCK+zMwHwYDVR0jBBgw
-FoAUvXg4wjfznAao6z6vWqGIJBSFW74wCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoG
-CCsGAQUFBwMBMIIdjwYDVR0RBIIdhjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVu
-b3Qtd2ViLXBsYXRmb3JtLnRlc3SCFW9wNi53ZWItcGxhdGZvcm0udGVzdIIVd3d3
-LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDEud2ViLXBsYXRmb3JtLnRlc3SCFW9wNy53
-ZWItcGxhdGZvcm0udGVzdIIVb3A4LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDIud2Vi
-LXBsYXRmb3JtLnRlc3SCFW9wOS53ZWItcGxhdGZvcm0udGVzdIIVb3A1LndlYi1w
-bGF0Zm9ybS50ZXN0ghVvcDQud2ViLXBsYXRmb3JtLnRlc3SCFW9wMy53ZWItcGxh
-dGZvcm0udGVzdIIWb3A0MC53ZWItcGxhdGZvcm0udGVzdIIWb3A2MS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzMy53ZWItcGxhdGZvcm0udGVzdIIWb3A3OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzOC53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxh
-dGZvcm0udGVzdIIWb3A0My53ZWItcGxhdGZvcm0udGVzdIIWb3A0NC53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxNC53ZWItcGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzNi53ZWItcGxhdGZvcm0udGVzdIIWb3AyMS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2MC53ZWItcGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A1Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxOC53ZWItcGxhdGZvcm0udGVzdIIWb3A1Ny53ZWItcGxh
-dGZvcm0udGVzdIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A0MS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ny53ZWItcGxh
-dGZvcm0udGVzdIIWb3A1Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyNS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxNi53ZWItcGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxMC53ZWItcGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxMi53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxh
-dGZvcm0udGVzdIIWb3A3NC53ZWItcGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxh
-dGZvcm0udGVzdIIWb3A0NS53ZWItcGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A0Mi53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzNC53ZWItcGxhdGZvcm0udGVzdIIWb3A0OC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A3NS53ZWItcGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxh
-dGZvcm0udGVzdIIWb3AyMi53ZWItcGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxh
-dGZvcm0udGVzdIIWb3A3My53ZWItcGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A5Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AzMi53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2NC53ZWItcGxhdGZvcm0udGVzdIIWb3AxMS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AxNS53ZWItcGxhdGZvcm0udGVzdIIWb3A4NS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A1OC53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4My53ZWItcGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2OC53ZWItcGxhdGZvcm0udGVzdIIWb3A5OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AzOS53ZWItcGxhdGZvcm0udGVzdIIWb3A1OS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A5NS53ZWItcGxhdGZvcm0udGVzdIIWb3A1My53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2My53ZWItcGxhdGZvcm0udGVzdIIWb3A1NC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A4OC53ZWItcGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxh
-dGZvcm0udGVzdIIWb3AyOC53ZWItcGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2Ni53ZWItcGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxh
-dGZvcm0udGVzdIIWb3A2Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A2NS53ZWItcGxh
-dGZvcm0udGVzdIIWb3AyNy53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ni53ZWItcGxh
-dGZvcm0udGVzdIIWb3A3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyOS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A5Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxh
-dGZvcm0udGVzdIIWb3A1NS53ZWItcGxhdGZvcm0udGVzdIIWb3A0Ni53ZWItcGxh
-dGZvcm0udGVzdIIWb3A3OC53ZWItcGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxh
-dGZvcm0udGVzdIIWb3AyNC53ZWItcGxhdGZvcm0udGVzdIIWb3A4MS53ZWItcGxh
-dGZvcm0udGVzdIIZb3A3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A0Lm5vdC13
-ZWItcGxhdGZvcm0udGVzdIIZb3A4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3
-Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZb3A5Lm5vdC13ZWItcGxhdGZvcm0udGVz
-dIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIZb3AzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A1Lm5vdC13ZWIt
-cGxhdGZvcm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A2Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3AyNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wOTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDc1Lm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIab3A1NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjUubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDI4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5
-Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDk1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1My5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wMzcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQxLm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3A2OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wODcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cxLnd3dy53ZWItcGxhdGZv
-cm0udGVzdIIab3A3MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODMubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDkxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4
-MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTkubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDQ4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2NC5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wNzYubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3
-Mi53ZWItcGxhdGZvcm0udGVzdIIab3AyNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wNzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3MS53ZWItcGxhdGZv
-cm0udGVzdIIab3A3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTUubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDcyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2
-NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTgubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDQ5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1MC5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ3Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3A4Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wMTIubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDI3Lm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIab3A4OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODYubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDUyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Ay
-MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjMubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDYzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0Mi5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wNzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYyLm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3AxMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wNTgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDY2Lm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIad3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzEubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDM5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3
-My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzcubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDU1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A2OS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wNTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk2Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3AxNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wMTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghp3d3cyLnd3dy53ZWItcGxhdGZv
-cm0udGVzdIIab3A2MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjEubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDgwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5
-MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjcubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDQzLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1OS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wNDQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE0Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3AxOS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wMzMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDIyLm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIab3A4OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjAubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDQwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0
-Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDU2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyOS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wMzQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDk3Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIab3A4NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
-Gm9wMzUubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDkzLm5vdC13ZWItcGxhdGZv
-cm0udGVzdIIab3A3OS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTgubm90LXdl
-Yi1wbGF0Zm9ybS50ZXN0ghpvcDU3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Az
-Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTEubm90LXdlYi1wbGF0Zm9ybS50
-ZXN0ghpvcDM4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4NS5ub3Qtd2ViLXBs
-YXRmb3JtLnRlc3SCGm9wMzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ1Lm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIbd3d3Mi53d3cyLndlYi1wbGF0Zm9ybS50ZXN0
-ght3d3cxLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCG3d3dzEud3d3Mi53ZWItcGxh
-dGZvcm0udGVzdIIbd3d3Mi53d3cxLndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3
-Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3MS53d3cubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0gh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCHnd3dy53d3cy
+AAOCAQ8AMIIBCgKCAQEA3MIXc4hL9lgJLyv8KXnJ+S0QKa21kY2qLWnF75LaMUtG
+itn39+MIlexqwbnMcVPNYtywrnJ3fNnRk+Lx380yimm+f/r7rdRTaBuQSphmGQqT
+qOjGTlgCSeM12EAQBHirq0o4Jczl1po0qQBMzPU6lBuupaaEiufM7+4J3g24w5yY
+WymGULqzTptzyzHdHqd/8sasKlYmtZzp/sWuGaBa1sILlgysdPcoQShFQx17QBn2
+afRFgE6rhLKhUqHi6skA733uR3n4uHT5mN9joiRuAK0inoMckXpEGfBOMd5p5bd6
+awup2RXsSxutFDosfwDd0Yn6Rw3svGavy6RrMvjU+wIDAQABo4IeBDCCHgAwCQYD
+VR0TBAIwADAdBgNVHQ4EFgQUzfHIYtHspT3kGpFw8QLmbrwv4gUwHwYDVR0jBBgw
+FoAU3G2NYt1UmMhgF8LTUbO/c1tckLkwCwYDVR0PBAQDAgXgMBMGA1UdJQQMMAoG
+CCsGAQUFBwMBMIIdjwYDVR0RBIIdhjCCHYKCEXdlYi1wbGF0Zm9ybS50ZXN0ghVv
+cDgud2ViLXBsYXRmb3JtLnRlc3SCFW9wNy53ZWItcGxhdGZvcm0udGVzdIIVb3A5
+LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDQud2ViLXBsYXRmb3JtLnRlc3SCFW5vdC13
+ZWItcGxhdGZvcm0udGVzdIIVb3A2LndlYi1wbGF0Zm9ybS50ZXN0ghVvcDMud2Vi
+LXBsYXRmb3JtLnRlc3SCFW9wMi53ZWItcGxhdGZvcm0udGVzdIIVb3AxLndlYi1w
+bGF0Zm9ybS50ZXN0ghV3d3cud2ViLXBsYXRmb3JtLnRlc3SCFW9wNS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4OC53ZWItcGxhdGZvcm0udGVzdIIWb3A5OC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4NS53ZWItcGxhdGZvcm0udGVzdIIWb3A4OS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A3Mi53ZWItcGxh
+dGZvcm0udGVzdIIWb3AyNC53ZWItcGxhdGZvcm0udGVzdIIWb3A0MS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A3OS53ZWItcGxhdGZvcm0udGVzdIIWb3A5MS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A1OS53ZWItcGxhdGZvcm0udGVzdIIWb3AzOS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2MC53ZWItcGxhdGZvcm0udGVzdIIWb3A1OC53ZWItcGxh
+dGZvcm0udGVzdIIWb3AyOC53ZWItcGxhdGZvcm0udGVzdIIWd3d3MS53ZWItcGxh
+dGZvcm0udGVzdIIWb3AxNC53ZWItcGxhdGZvcm0udGVzdIIWb3A2OS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0MC53ZWItcGxhdGZvcm0udGVzdIIWb3A3NC53ZWItcGxh
+dGZvcm0udGVzdIIWb3AzMS53ZWItcGxhdGZvcm0udGVzdIIWb3AxOC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A3My53ZWItcGxhdGZvcm0udGVzdIIWb3A3Ny53ZWItcGxh
+dGZvcm0udGVzdIIWb3AxMi53ZWItcGxhdGZvcm0udGVzdIIWb3A1NC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2My53ZWItcGxhdGZvcm0udGVzdIIWb3A3MS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A5NS53ZWItcGxhdGZvcm0udGVzdIIWb3AxNi53ZWItcGxh
+dGZvcm0udGVzdIIWb3AzNi53ZWItcGxhdGZvcm0udGVzdIIWb3AyNy53ZWItcGxh
+dGZvcm0udGVzdIIWb3AyOS53ZWItcGxhdGZvcm0udGVzdIIWb3A5NC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMy53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4NC53ZWItcGxhdGZvcm0udGVzdIIWb3AzMi53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2MS53ZWItcGxhdGZvcm0udGVzdIIWb3A3MC53ZWItcGxh
+dGZvcm0udGVzdIIWd3d3Mi53ZWItcGxhdGZvcm0udGVzdIIWb3A0My53ZWItcGxh
+dGZvcm0udGVzdIIWb3A3OC53ZWItcGxhdGZvcm0udGVzdIIWb3AyNi53ZWItcGxh
+dGZvcm0udGVzdIIWb3A3Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A1Mi53ZWItcGxh
+dGZvcm0udGVzdIIWb3A5OS53ZWItcGxhdGZvcm0udGVzdIIWb3A4Ni53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0Ni53ZWItcGxhdGZvcm0udGVzdIIWb3AxNy53ZWItcGxh
+dGZvcm0udGVzdIIWb3A5MC53ZWItcGxhdGZvcm0udGVzdIIWb3A5My53ZWItcGxh
+dGZvcm0udGVzdIIWb3AxMC53ZWItcGxhdGZvcm0udGVzdIIWb3A1NS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A1MS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0NS53ZWItcGxhdGZvcm0udGVzdIIWb3A4MC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2OC53ZWItcGxhdGZvcm0udGVzdIIWb3A0OS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A1Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AzNS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2Ny53ZWItcGxhdGZvcm0udGVzdIIWb3A5Mi53ZWItcGxh
+dGZvcm0udGVzdIIWb3AxNS53ZWItcGxhdGZvcm0udGVzdIIWb3AxMy53ZWItcGxh
+dGZvcm0udGVzdIIWb3A3NS53ZWItcGxhdGZvcm0udGVzdIIWb3A2NC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A5Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AzNy53ZWItcGxh
+dGZvcm0udGVzdIIWb3A1Ni53ZWItcGxhdGZvcm0udGVzdIIWb3A2Mi53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyNS53ZWItcGxh
+dGZvcm0udGVzdIIWb3AxMS53ZWItcGxhdGZvcm0udGVzdIIWb3A1MC53ZWItcGxh
+dGZvcm0udGVzdIIWb3AzOC53ZWItcGxhdGZvcm0udGVzdIIWb3A4My53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4MS53ZWItcGxhdGZvcm0udGVzdIIWb3AyMC53ZWItcGxh
+dGZvcm0udGVzdIIWb3AyMS53ZWItcGxhdGZvcm0udGVzdIIWb3AyMy53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0Mi53ZWItcGxhdGZvcm0udGVzdIIWb3AyMi53ZWItcGxh
+dGZvcm0udGVzdIIWb3A2NS53ZWItcGxhdGZvcm0udGVzdIIWb3A5Ni53ZWItcGxh
+dGZvcm0udGVzdIIWb3A4Ny53ZWItcGxhdGZvcm0udGVzdIIWb3AxOS53ZWItcGxh
+dGZvcm0udGVzdIIWb3A1My53ZWItcGxhdGZvcm0udGVzdIIWb3AzMC53ZWItcGxh
+dGZvcm0udGVzdIIWb3A0OC53ZWItcGxhdGZvcm0udGVzdIIWb3AzNC53ZWItcGxh
+dGZvcm0udGVzdIIZb3A2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AzLm5vdC13
+ZWItcGxhdGZvcm0udGVzdIIZb3AyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A1
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZd3d3Lm5vdC13ZWItcGxhdGZvcm0udGVz
+dIIZd3d3Lnd3dy53ZWItcGxhdGZvcm0udGVzdIIZb3A3Lm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIZb3A0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3A4Lm5vdC13ZWIt
+cGxhdGZvcm0udGVzdIIZb3A5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIZb3AxLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3AzNi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wNTMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDUwLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3AyNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzEubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDk1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4
+My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDczLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxOS5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wMjEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDgxLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3A3MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wNzgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQwLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3AyNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjUubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghp3d3cud3d3Mi53ZWItcGxhdGZvcm0udGVzdIIab3A4
+MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTIubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDY4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0NS5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wNzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDcyLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3A5MC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wODkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQ5Lm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3A3Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNzkubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDgyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIad3d3
+Lnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCGm9wMTIubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDM5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A0NC5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGnd3dzEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU4Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3AxNC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wMzAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDYyLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3A2MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wOTIubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDI5Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5
+OC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNjQubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDI2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AyMi5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wOTQubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDM4Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3AzMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wMjMubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDU3Lm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3A1NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wODUubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDQ2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5
+Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzIubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDYwLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A5Ni5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wNTEubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQxLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3AzNS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wOTkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQyLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3A2Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMzcubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDQ4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A1
+NS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTYubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDg0Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AzNC5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wNjkubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDExLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3A5My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gnd3dzEud3d3LndlYi1wbGF0Zm9ybS50ZXN0ghpvcDg2Lm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3AxMy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMjAubm90LXdl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDc2Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3Ay
+Ny5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wMTcubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDc1Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3AxNS5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wNDcubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE4Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIab3A2My5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SC
+Gm9wMjgubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDQzLm5vdC13ZWItcGxhdGZv
+cm0udGVzdIIab3A2Ni5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGnd3dzIud3d3Lndl
+Yi1wbGF0Zm9ybS50ZXN0ghpvcDkxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A3
+NC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCGm9wNTkubm90LXdlYi1wbGF0Zm9ybS50
+ZXN0ghpvcDg4Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIab3A4Ny5ub3Qtd2ViLXBs
+YXRmb3JtLnRlc3SCGm9wMTAubm90LXdlYi1wbGF0Zm9ybS50ZXN0ghpvcDE2Lm5v
+dC13ZWItcGxhdGZvcm0udGVzdIIbd3d3MS53d3cyLndlYi1wbGF0Zm9ybS50ZXN0
+ght3d3cyLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCG3d3dzIud3d3MS53ZWItcGxh
+dGZvcm0udGVzdIIbd3d3MS53d3cxLndlYi1wbGF0Zm9ybS50ZXN0gh13d3cud3d3
+Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIeeG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9y
+bS50ZXN0gh53d3cxLnd3dy5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCHnd3dy53d3cy
 Lm5vdC13ZWItcGxhdGZvcm0udGVzdIIed3d3Mi53d3cubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0gh54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3
-MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRm
-b3JtLnRlc3SCH3d3dzIud3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEu
+bS50ZXN0gh53d3cud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3
+Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzIud3d3MS5ub3Qtd2ViLXBsYXRm
+b3JtLnRlc3SCH3d3dzEud3d3MS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCH3d3dzEu
 d3d3Mi5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC53d3cud2Vi
-LXBsYXRmb3JtLnRlc3SCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRl
-c3SCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCI3huLS1sdmUt
-NmxhZC53d3cxLndlYi1wbGF0Zm9ybS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53
-ZWItcGxhdGZvcm0udGVzdIIjd3d3Mi54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3Jt
+LXBsYXRmb3JtLnRlc3SCInhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCInd3dy54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCI3d3dzIueG4t
+LWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giN4bi0tbHZlLTZsYWQud3d3Mi53
+ZWItcGxhdGZvcm0udGVzdIIjeG4tLWx2ZS02bGFkLnd3dzEud2ViLXBsYXRmb3Jt
 LnRlc3SCI3d3dzEueG4tLWx2ZS02bGFkLndlYi1wbGF0Zm9ybS50ZXN0giZ4bi0t
 bHZlLTZsYWQud3d3Lm5vdC13ZWItcGxhdGZvcm0udGVzdIImd3d3LnhuLS1sdmUt
-NmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3d3dzEueG4tLWx2ZS02bGFkLm5v
-dC13ZWItcGxhdGZvcm0udGVzdIIneG4tLWx2ZS02bGFkLnd3dzEubm90LXdlYi1w
-bGF0Zm9ybS50ZXN0gid4bi0tbHZlLTZsYWQud3d3Mi5ub3Qtd2ViLXBsYXRmb3Jt
-LnRlc3SCJ3d3dzIueG4tLWx2ZS02bGFkLm5vdC13ZWItcGxhdGZvcm0udGVzdIIp
+NmxhZC5ub3Qtd2ViLXBsYXRmb3JtLnRlc3SCJ3huLS1sdmUtNmxhZC53d3cxLm5v
+dC13ZWItcGxhdGZvcm0udGVzdIInd3d3Mi54bi0tbHZlLTZsYWQubm90LXdlYi1w
+bGF0Zm9ybS50ZXN0gid3d3cxLnhuLS1sdmUtNmxhZC5ub3Qtd2ViLXBsYXRmb3Jt
+LnRlc3SCJ3huLS1sdmUtNmxhZC53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIp
 eG4tLW44ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCK3huLS1s
-dmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCLXhuLS1uOGo2
-ZHM1M2x3d2tycWh2MjhhLnd3dy53ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZk
-czUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gi13d3cueG4tLW44
-ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44
-ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44
+dmUtNmxhZC54bi0tbHZlLTZsYWQud2ViLXBsYXRmb3JtLnRlc3SCLXd3dy54bi0t
+bjhqNmRzNTNsd3drcnFodjI4YS53ZWItcGxhdGZvcm0udGVzdIIteG4tLW44ajZk
+czUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gi14bi0tbjhqNmRz
+NTNsd3drcnFodjI4YS53d3cud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzEueG4tLW44
 ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1
-M2x3d2tycWh2MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1
-M2x3d2tycWh2MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxh
+M2x3d2tycWh2MjhhLnd3dzIud2ViLXBsYXRmb3JtLnRlc3SCLnhuLS1uOGo2ZHM1
+M2x3d2tycWh2MjhhLnd3dzEud2ViLXBsYXRmb3JtLnRlc3SCLnd3dzIueG4tLW44
+ajZkczUzbHd3a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCL3huLS1sdmUtNmxh
 ZC54bi0tbHZlLTZsYWQubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF3d3cueG4tLW44
 ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjF4bi0tbjhq
 NmRzNTNsd3drcnFodjI4YS53d3cubm90LXdlYi1wbGF0Zm9ybS50ZXN0gjJ4bi0t
-bjhqNmRzNTNsd3drcnFodjI4YS53d3cxLm5vdC13ZWItcGxhdGZvcm0udGVzdIIy
-d3d3Mi54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRl
-c3SCMnd3dzEueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9y
-bS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxh
+bjhqNmRzNTNsd3drcnFodjI4YS53d3cyLm5vdC13ZWItcGxhdGZvcm0udGVzdIIy
+d3d3MS54bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRl
+c3SCMnd3dzIueG4tLW44ajZkczUzbHd3a3JxaHYyOGEubm90LXdlYi1wbGF0Zm9y
+bS50ZXN0gjJ4bi0tbjhqNmRzNTNsd3drcnFodjI4YS53d3cxLm5vdC13ZWItcGxh
 dGZvcm0udGVzdII2eG4tLW44ajZkczUzbHd3a3JxaHYyOGEueG4tLWx2ZS02bGFk
 LndlYi1wbGF0Zm9ybS50ZXN0gjZ4bi0tbHZlLTZsYWQueG4tLW44ajZkczUzbHd3
 a3JxaHYyOGEud2ViLXBsYXRmb3JtLnRlc3SCOnhuLS1uOGo2ZHM1M2x3d2tycWh2
@@ -231,10 +231,10 @@
 c3SCQXhuLS1uOGo2ZHM1M2x3d2tycWh2MjhhLnhuLS1uOGo2ZHM1M2x3d2tycWh2
 MjhhLndlYi1wbGF0Zm9ybS50ZXN0gkV4bi0tbjhqNmRzNTNsd3drcnFodjI4YS54
 bi0tbjhqNmRzNTNsd3drcnFodjI4YS5ub3Qtd2ViLXBsYXRmb3JtLnRlc3QwDQYJ
-KoZIhvcNAQELBQADggEBACD/IHHlLZ8WSvC478sjY1ZwvIzGaw769YBVWvV1WM3G
-fmZtETPv/KZrW5gE1Wtb7o08CxPU+Wtum7Wtpm4F1NP1/7GnF0aOmHuJhxSkwfom
-Am1ExcjGWtKc6DKDq3cHgMiAqx/GVnruf6odazfh1cEEVOUwQemlnvB9j/UkYPAk
-ecvS6C2VM53KmAIRN0eXQxPCinOj4RTLht5wwrHVW9lt9q1vzKUrmyGL13gDXCvk
-+ELFfQ0HsOFB7awmlZPbEpujbv+QYg0QrtX0hz06UFXHxOBIU5HpIuuXpjFCKz8k
-BhJckv9pXq8A/ebsLWYwf1nb0W+8LfSL03Ql4aVGeS0=
+KoZIhvcNAQELBQADggEBADin7+tVMOhvv1Gp61KaZuw9GV30HYQXwPImPitmXXqp
+RIbDutfwnueyswUMJe/ht5SMRBzSV0wwUZYpli6z4xz4nOZ9lhQ/Pz6mlksB3PLt
+v/zjZJNJgb7J3d0bztpyRdEtypnN0X35F+HuEvTtdkHKb6VccgBKjXbFK7cYe87o
+q3aadekdU5t1k20LLkk/v4Qfcb5JI6ss+KaiKJOCBGyOhSIOtm3FHoLRDcYImoah
+KVx5U9Ou1sQzS9IEWtmgw20m7Og1BueIEgN8xYMmsrUyo0FRtJSwhA1KBVICKUFb
+AwTww+Uk5lrvcEVFWCUrXr59ynMCKx1PPEsA9GlfGm4=
 -----END CERTIFICATE-----
diff --git a/third_party/wpt_tools/wpt/tools/gitignore/gitignore.py b/third_party/wpt_tools/wpt/tools/gitignore/gitignore.py
index 500fe783..dbe83c2 100644
--- a/third_party/wpt_tools/wpt/tools/gitignore/gitignore.py
+++ b/third_party/wpt_tools/wpt/tools/gitignore/gitignore.py
@@ -1,7 +1,7 @@
 import re
 import os
 import itertools
-from six import ensure_binary
+from six import ensure_binary, itervalues, iteritems
 from collections import defaultdict
 
 MYPY = False
@@ -194,13 +194,13 @@
                 rule = cast(Tuple[bool, Pattern[bytes]], rule)
             if not dir_only:
                 rules_iter = itertools.chain(
-                    itertools.chain(*(item.items() for item in self.literals_dir.values())),
-                    itertools.chain(*(item.items() for item in self.literals_file.values())),
+                    itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
+                    itertools.chain(*(iteritems(item) for item in itervalues(self.literals_file))),
                     self.patterns_dir,
                     self.patterns_file)  # type: Iterable[Tuple[Any, List[Tuple[bool, Pattern[bytes]]]]]
             else:
                 rules_iter = itertools.chain(
-                    itertools.chain(*(item.items() for item in self.literals_dir.values())),
+                    itertools.chain(*(iteritems(item) for item in itervalues(self.literals_dir))),
                     self.patterns_dir)
 
             for rules in rules_iter:
diff --git a/third_party/wpt_tools/wpt/tools/lint/lint.py b/third_party/wpt_tools/wpt/tools/lint/lint.py
index d8fb9fc..f936055 100644
--- a/third_party/wpt_tools/wpt/tools/lint/lint.py
+++ b/third_party/wpt_tools/wpt/tools/lint/lint.py
@@ -14,7 +14,6 @@
 import tempfile
 
 from collections import defaultdict
-from urllib.parse import urlsplit, urljoin
 
 from . import fnmatch
 from . import rules
@@ -25,7 +24,9 @@
 from ..manifest.vcs import walk
 
 from ..manifest.sourcefile import SourceFile, js_meta_re, python_meta_re, space_chars, get_any_variants
-from six import ensure_binary, ensure_text
+from six import binary_type, ensure_binary, ensure_text, iteritems, itervalues, with_metaclass
+from six.moves import range
+from six.moves.urllib.parse import urlsplit, urljoin
 
 MYPY = False
 if MYPY:
@@ -324,7 +325,7 @@
 
     errors = []
 
-    for name, colliding in test_files.items():
+    for name, colliding in iteritems(test_files):
         if len(colliding) > 1:
             if not _all_files_equal([os.path.join(repo_root, x) for x in colliding]):
                 # Only compute by_spec if there are prima-facie collisions because of cost
@@ -341,7 +342,7 @@
                             continue
                         by_spec[spec].add(path)
 
-                for spec, spec_paths in by_spec.items():
+                for spec, spec_paths in iteritems(by_spec):
                     if not _all_files_equal([os.path.join(repo_root, x) for x in spec_paths]):
                         for x in spec_paths:
                             context1 = (name, spec, ", ".join(sorted(spec_paths)))
@@ -350,7 +351,7 @@
 
     for rule_class, d in [(rules.CSSCollidingRefName, ref_files),
                           (rules.CSSCollidingSupportName, support_files)]:
-        for name, colliding in d.items():
+        for name, colliding in iteritems(d):
             if len(colliding) > 1:
                 if not _all_files_equal([os.path.join(repo_root, x) for x in colliding]):
                     context2 = (name, ", ".join(sorted(colliding)))
@@ -450,7 +451,7 @@
         # which explains how to fix it correctly and shouldn't be skipped.
         if error_type in data and error_type != "IGNORED PATH":
             wl_files = data[error_type]
-            for file_match, allowed_lines in wl_files.items():
+            for file_match, allowed_lines in iteritems(wl_files):
                 if None in allowed_lines or line in allowed_lines:
                     if fnmatch.fnmatchcase(normpath, file_match):
                         skipped[i] = True
@@ -667,7 +668,7 @@
 
     return errors
 
-class ASTCheck(metaclass=abc.ABCMeta):
+class ASTCheck(with_metaclass(abc.ABCMeta)):
     @abc.abstractproperty
     def rule(self):
         # type: () -> Type[rules.Rule]
@@ -740,7 +741,7 @@
     done = False
     errors = []
     for idx, line in enumerate(f):
-        assert isinstance(line, bytes), line
+        assert isinstance(line, binary_type), line
 
         m = meta_re.match(line)
         if m:
@@ -974,7 +975,7 @@
 
 def main(**kwargs_str):
     # type: (**Any) -> int
-    kwargs = {ensure_text(key): value for key, value in kwargs_str.items()}
+    kwargs = {ensure_text(key): value for key, value in iteritems(kwargs_str)}
 
     assert logger is not None
     if kwargs.get("json") and kwargs.get("markdown"):
@@ -1102,7 +1103,7 @@
     if error_count and github_checks_outputter:
         github_checks_outputter.output("```")
 
-    return sum(error_count.values())
+    return sum(itervalues(error_count))
 
 
 path_lints = [check_file_type, check_path_length, check_worker_collision, check_ahem_copy,
diff --git a/third_party/wpt_tools/wpt/tools/lint/rules.py b/third_party/wpt_tools/wpt/tools/lint/rules.py
index e9bb30b5..b389e3d 100644
--- a/third_party/wpt_tools/wpt/tools/lint/rules.py
+++ b/third_party/wpt_tools/wpt/tools/lint/rules.py
@@ -5,6 +5,8 @@
 import os
 import re
 
+import six
+
 MYPY = False
 if MYPY:
     # MYPY is set to True when run under Mypy.
@@ -17,7 +19,7 @@
     return inspect.cleandoc(str(text)).replace("\n", " ")
 
 
-class Rule(metaclass=abc.ABCMeta):
+class Rule(six.with_metaclass(abc.ABCMeta)):
     @abc.abstractproperty
     def name(self):
         # type: () -> Text
@@ -365,7 +367,7 @@
     to_fix = "rename directory to be called 'tentative'"
 
 
-class Regexp(metaclass=abc.ABCMeta):
+class Regexp(six.with_metaclass(abc.ABCMeta)):
     @abc.abstractproperty
     def pattern(self):
         # type: () -> bytes
diff --git a/third_party/wpt_tools/wpt/tools/localpaths.py b/third_party/wpt_tools/wpt/tools/localpaths.py
index 1cb6f5b3..a79acb82 100644
--- a/third_party/wpt_tools/wpt/tools/localpaths.py
+++ b/third_party/wpt_tools/wpt/tools/localpaths.py
@@ -18,7 +18,6 @@
 sys.path.insert(0, os.path.join(here, "third_party", "py"))
 sys.path.insert(0, os.path.join(here, "third_party", "pytest"))
 sys.path.insert(0, os.path.join(here, "third_party", "pytest", "src"))
-sys.path.insert(0, os.path.join(here, "third_party", "pytest-asyncio"))
 sys.path.insert(0, os.path.join(here, "third_party", "six"))
 sys.path.insert(0, os.path.join(here, "third_party", "webencodings"))
 sys.path.insert(0, os.path.join(here, "third_party", "h2"))
@@ -26,8 +25,6 @@
 sys.path.insert(0, os.path.join(here, "third_party", "hyperframe"))
 sys.path.insert(0, os.path.join(here, "third_party", "certifi"))
 sys.path.insert(0, os.path.join(here, "third_party", "hyper"))
-sys.path.insert(0, os.path.join(here, "third_party", "websockets", "src"))
-sys.path.insert(0, os.path.join(here, "third_party", "iniconfig", "src"))
 if sys.version_info < (3, 8):
     sys.path.insert(0, os.path.join(here, "third_party", "importlib_metadata"))
 sys.path.insert(0, os.path.join(here, "webdriver"))
diff --git a/third_party/wpt_tools/wpt/tools/manifest/XMLParser.py b/third_party/wpt_tools/wpt/tools/manifest/XMLParser.py
index 45a8a54..80aa3b5 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/XMLParser.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/XMLParser.py
@@ -6,6 +6,8 @@
 from xml.parsers import expat
 import xml.etree.ElementTree as etree  # noqa: N813
 
+from six import text_type
+
 MYPY = False
 if MYPY:
     # MYPY is set to True when run under Mypy.
@@ -81,7 +83,7 @@
 
     def _start(self, tag, attrib_in):
         # type: (Text, List[str]) -> etree.Element
-        assert isinstance(tag, str)
+        assert isinstance(tag, text_type)
         self._fed_data = None
         tag = _fixname(tag)
         attrib = OrderedDict()  # type: Dict[Union[bytes, Text], Union[bytes, Text]]
diff --git a/third_party/wpt_tools/wpt/tools/manifest/download.py b/third_party/wpt_tools/wpt/tools/manifest/download.py
index 88d478f..9d76318 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/download.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/download.py
@@ -7,7 +7,8 @@
 import io
 import os
 from datetime import datetime, timedelta
-from urllib.request import urlopen
+
+from six.moves.urllib.request import urlopen
 
 try:
     import zstandard
diff --git a/third_party/wpt_tools/wpt/tools/manifest/item.py b/third_party/wpt_tools/wpt/tools/manifest/item.py
index 4b973d5..857c8485 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/item.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/item.py
@@ -1,6 +1,7 @@
 import os.path
 from inspect import isabstract
-from urllib.parse import urljoin, urlparse, parse_qs
+from six import iteritems, with_metaclass
+from six.moves.urllib.parse import urljoin, urlparse, parse_qs
 from abc import ABCMeta, abstractproperty
 
 from .utils import to_os_path
@@ -41,7 +42,7 @@
         return rv  # type: ignore
 
 
-class ManifestItem(metaclass=ManifestItemMeta):
+class ManifestItem(with_metaclass(ManifestItemMeta)):
     __slots__ = ("_tests_root", "path")
 
     def __init__(self, tests_root, path):
@@ -288,7 +289,7 @@
         if self.dpi is not None:
             extras["dpi"] = self.dpi
         if self.fuzzy:
-            extras["fuzzy"] = list(self.fuzzy.items())
+            extras["fuzzy"] = list(iteritems(self.fuzzy))
         return rv
 
     @classmethod
diff --git a/third_party/wpt_tools/wpt/tools/manifest/jsonlib.py b/third_party/wpt_tools/wpt/tools/manifest/jsonlib.py
index 49eaf02..e7f07c3 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/jsonlib.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/jsonlib.py
@@ -1,6 +1,8 @@
 import re
 import json
 
+from six import PY3
+
 
 MYPY = False
 if MYPY:
@@ -47,9 +49,11 @@
     'ensure_ascii': False,
     'escape_forward_slashes': False,
     'indent': 1,
-    'reject_bytes': True,
 }  # type: Dict[str, Any]
 
+if PY3:
+    _ujson_dump_local_kwargs['reject_bytes'] = True
+
 
 _json_dump_local_kwargs = {
     'ensure_ascii': False,
@@ -95,9 +99,10 @@
 _ujson_dump_dist_kwargs = {
     'sort_keys': True,
     'indent': 1,
-    'reject_bytes': True,
 }  # type: Dict[str, Any]
 
+if PY3:
+    _ujson_dump_dist_kwargs['reject_bytes'] = True
 
 _json_dump_dist_kwargs = {
     'sort_keys': True,
diff --git a/third_party/wpt_tools/wpt/tools/manifest/manifest.py b/third_party/wpt_tools/wpt/tools/manifest/manifest.py
index 9f1e902d..123f045 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/manifest.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/manifest.py
@@ -1,10 +1,17 @@
 import io
+import itertools
 import os
 import sys
 from atomicwrites import atomic_write
 from copy import deepcopy
 from multiprocessing import Pool, cpu_count
-from six import ensure_text
+from six import (
+    PY3,
+    ensure_text,
+    iteritems,
+    itervalues,
+    string_types,
+)
 
 from . import jsonlib
 from . import vcs
@@ -86,7 +93,7 @@
         """Dictionary subclass containing a TypeData instance for each test type,
         keyed by type name"""
         self.initialized = False  # type: bool
-        for key, value in item_classes.items():
+        for key, value in iteritems(item_classes):
             self[key] = TypeData(manifest, value)
         self.initialized = True
         self.json_obj = None  # type: None
@@ -102,7 +109,7 @@
         """Get a list of all paths containing test items
         without actually constructing all the items"""
         rv = set()  # type: Set[Text]
-        for item_data in self.values():
+        for item_data in itervalues(self):
             for item in item_data:
                 rv.add(os.path.sep.join(item))
         return rv
@@ -110,7 +117,7 @@
     def type_by_path(self):
         # type: () -> Dict[Tuple[Text, ...], Text]
         rv = {}
-        for item_type, item_data in self.items():
+        for item_type, item_data in iteritems(self):
             for item in item_data:
                 rv[item] = item_type
         return rv
@@ -152,7 +159,7 @@
         tpath_len = len(tpath)
 
         for type_tests in self._data.values():
-            for path, tests in type_tests.items():
+            for path, tests in iteritems(type_tests):
                 if path[:tpath_len] == tpath:
                     for test in tests:
                         yield test
@@ -246,8 +253,10 @@
                                           to_update,
                                           chunksize=chunksize
                                           )  # type: Iterator[Tuple[Tuple[Text, ...], Text, Set[ManifestItem], Text]]
-        else:
+        elif PY3:
             results = map(compute_manifest_items, to_update)
+        else:
+            results = itertools.imap(compute_manifest_items, to_update)
 
         for result in results:
             rel_path_parts, new_type, manifest_items, file_hash = result
@@ -262,7 +271,7 @@
         if remaining_manifest_paths:
             changed = True
             for rel_path_parts in remaining_manifest_paths:
-                for test_data in data.values():
+                for test_data in itervalues(data):
                     if rel_path_parts in test_data:
                         del test_data[rel_path_parts]
 
@@ -282,7 +291,7 @@
         """
         out_items = {
             test_type: type_paths.to_json()
-            for test_type, type_paths in self._data.items() if type_paths
+            for test_type, type_paths in iteritems(self._data) if type_paths
         }
 
         if caller_owns_obj:
@@ -316,7 +325,7 @@
         if not hasattr(obj, "items"):
             raise ManifestError
 
-        for test_type, type_paths in obj["items"].items():
+        for test_type, type_paths in iteritems(obj["items"]):
             if test_type not in item_classes:
                 raise ManifestError
 
@@ -349,12 +358,12 @@
           allow_cached=True  # type: bool
           ):
     # type: (...) -> Optional[Manifest]
-    manifest_path = (manifest if isinstance(manifest, str)
+    manifest_path = (manifest if isinstance(manifest, string_types)
                      else manifest.name)
     if allow_cached and manifest_path in __load_cache:
         return __load_cache[manifest_path]
 
-    if isinstance(manifest, str):
+    if isinstance(manifest, string_types):
         if os.path.exists(manifest):
             logger.debug("Opening manifest at %s" % manifest)
         else:
diff --git a/third_party/wpt_tools/wpt/tools/manifest/sourcefile.py b/third_party/wpt_tools/wpt/tools/manifest/sourcefile.py
index 34e679e..ce81c625 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/sourcefile.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/sourcefile.py
@@ -3,7 +3,8 @@
 import os
 from collections import deque
 from io import BytesIO
-from urllib.parse import urljoin
+from six import binary_type, iteritems, text_type
+from six.moves.urllib.parse import urljoin
 from fnmatch import fnmatch
 
 MYPY = False
@@ -73,7 +74,7 @@
                value.
     """
     for line in f:
-        assert isinstance(line, bytes), line
+        assert isinstance(line, binary_type), line
         m = regexp.match(line)
         if not m:
             break
@@ -84,13 +85,9 @@
 _any_variants = {
     "window": {"suffix": ".any.html"},
     "serviceworker": {"force_https": True},
-    "serviceworker-module": {"force_https": True},
     "sharedworker": {},
-    "sharedworker-module": {},
     "dedicatedworker": {"suffix": ".any.worker.html"},
-    "dedicatedworker-module": {"suffix": ".any.worker-module.html"},
     "worker": {"longhand": {"dedicatedworker", "sharedworker", "serviceworker"}},
-    "worker-module": {},
     "jsshell": {"suffix": ".any.js"},
 }  # type: Dict[Text, Dict[Text, Any]]
 
@@ -100,7 +97,7 @@
     """
     Returns a set of variants (strings) defined by the given keyword.
     """
-    assert isinstance(item, str), item
+    assert isinstance(item, text_type), item
 
     variant = _any_variants.get(item, None)
     if variant is None:
@@ -122,7 +119,7 @@
     """
     Returns a set of variants (strings) defined by a comma-separated value.
     """
-    assert isinstance(value, str), value
+    assert isinstance(value, text_type), value
 
     if value == "":
         return get_default_any_variants()
@@ -141,7 +138,7 @@
     variant is intended to run in a JS shell, for the variants defined by the
     given comma-separated value.
     """
-    assert isinstance(value, str), value
+    assert isinstance(value, text_type), value
 
     rv = set()
 
@@ -246,7 +243,7 @@
 
         if "__cached_properties__" in rv:
             cached_properties = rv["__cached_properties__"]
-            rv = {key:value for key, value in rv.items() if key not in cached_properties}
+            rv = {key:value for key, value in iteritems(rv) if key not in cached_properties}
             del rv["__cached_properties__"]
         return rv
 
@@ -307,7 +304,7 @@
                 content = f.read()
 
             data = b"".join((b"blob ", b"%d" % len(content), b"\0", content))
-            self._hash = str(hashlib.sha1(data).hexdigest())
+            self._hash = text_type(hashlib.sha1(data).hexdigest())
 
         return self._hash
 
diff --git a/third_party/wpt_tools/wpt/tools/manifest/testpaths.py b/third_party/wpt_tools/wpt/tools/manifest/testpaths.py
index 6902f0c..2197792c 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/testpaths.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/testpaths.py
@@ -3,6 +3,8 @@
 import os
 from collections import defaultdict
 
+from six import iteritems
+
 from .manifest import load_and_update, Manifest
 from .log import get_logger
 
@@ -100,7 +102,7 @@
     if as_json:
         print(json.dumps(path_id_map))
     else:
-        for path, test_ids in sorted(path_id_map.items()):
+        for path, test_ids in sorted(iteritems(path_id_map)):
             print(path)
             for test_id in sorted(test_ids):
                 print("  " + test_id)
diff --git a/third_party/wpt_tools/wpt/tools/manifest/typedata.py b/third_party/wpt_tools/wpt/tools/manifest/typedata.py
index 174008e..01bb827 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/typedata.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/typedata.py
@@ -1,4 +1,5 @@
-from collections.abc import MutableMapping
+from six import itervalues, iteritems
+from six.moves.collections_abc import MutableMapping
 
 
 MYPY = False
@@ -180,7 +181,7 @@
             if isinstance(v, set):
                 count += 1
             else:
-                stack.extend(v.values())
+                stack.extend(itervalues(v))
 
         stack = [self._json_data]
         while stack:
@@ -188,7 +189,7 @@
             if isinstance(v, list):
                 count += 1
             else:
-                stack.extend(v.values())
+                stack.extend(itervalues(v))
 
         return count
 
@@ -269,7 +270,7 @@
         stack = [(self._data, json_rv, tuple())]  # type: List[Tuple[Dict[Text, Any], Dict[Text, Any], Tuple[Text, ...]]]
         while stack:
             data_node, json_node, par_full_key = stack.pop()
-            for k, v in data_node.items():
+            for k, v in iteritems(data_node):
                 full_key = par_full_key + (k,)
                 if isinstance(v, set):
                     assert k not in json_node
diff --git a/third_party/wpt_tools/wpt/tools/manifest/vcs.py b/third_party/wpt_tools/wpt/tools/manifest/vcs.py
index 65ba308..4f3bfda 100644
--- a/third_party/wpt_tools/wpt/tools/manifest/vcs.py
+++ b/third_party/wpt_tools/wpt/tools/manifest/vcs.py
@@ -2,7 +2,9 @@
 import os
 import stat
 from collections import deque
-from collections.abc import MutableMapping
+
+from six import with_metaclass, PY2
+from six.moves.collections_abc import MutableMapping
 
 from . import jsonlib
 from .utils import git
@@ -17,7 +19,10 @@
     # MYPY is set to True when run under Mypy.
     from typing import Dict, Optional, List, Set, Text, Iterable, Any, Tuple, Iterator
     from .manifest import Manifest  # cyclic import under MYPY guard
-    stat_result = os.stat_result
+    if PY2:
+        stat_result = Any
+    else:
+        stat_result = os.stat_result
 
     GitIgnoreCacheType = MutableMapping[bytes, bool]
 else:
@@ -127,7 +132,7 @@
                 cache.dump()
 
 
-class CacheFile(metaclass=abc.ABCMeta):
+class CacheFile(with_metaclass(abc.ABCMeta)):
     def __init__(self, cache_root, tests_root, rebuild=False):
         # type: (Text, Text, bool) -> None
         self.tests_root = tests_root
diff --git a/third_party/wpt_tools/wpt/tools/quic/commands.json b/third_party/wpt_tools/wpt/tools/quic/commands.json
index 4496f48..d4e3ce8 100644
--- a/third_party/wpt_tools/wpt/tools/quic/commands.json
+++ b/third_party/wpt_tools/wpt/tools/quic/commands.json
@@ -3,6 +3,7 @@
     "path": "serve.py",
     "script": "run",
     "parser": "get_parser",
+    "py3only": true,
     "help": "Start the QUIC server for WebTransport",
     "virtualenv": true,
     "requirements": [
diff --git a/third_party/wpt_tools/wpt/tools/serve/serve.py b/third_party/wpt_tools/wpt/tools/serve/serve.py
index 8e1aaa8..f09fe24 100644
--- a/third_party/wpt_tools/wpt/tools/serve/serve.py
+++ b/third_party/wpt_tools/wpt/tools/serve/serve.py
@@ -4,7 +4,6 @@
 
 import abc
 import argparse
-import importlib
 import json
 import logging
 import multiprocessing
@@ -17,12 +16,13 @@
 import threading
 import time
 import traceback
-import urllib
+from six.moves import urllib
 import uuid
 from collections import defaultdict, OrderedDict
 from itertools import chain, product
 
 from localpaths import repo_root
+from six.moves import reload_module
 
 from manifest.sourcefile import read_script_metadata, js_meta_re, parse_variants
 from wptserve import server as wptserve, handlers
@@ -227,22 +227,6 @@
 """
 
 
-class WorkerModulesHandler(HtmlWrapperHandler):
-    global_type = "dedicatedworker-module"
-    path_replace = [(".any.worker-module.html", ".any.js", ".any.worker-module.js"),
-                    (".worker.html", ".worker.js")]
-    wrapper = """<!doctype html>
-<meta charset=utf-8>
-%(meta)s
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
-<script>
-fetch_tests_from_worker(new Worker("%(path)s%(query)s", { type: "module" }));
-</script>
-"""
-
-
 class WindowHandler(HtmlWrapperHandler):
     path_replace = [(".window.html", ".window.js")]
     wrapper = """<!doctype html>
@@ -291,21 +275,6 @@
 """
 
 
-class SharedWorkerModulesHandler(HtmlWrapperHandler):
-    global_type = "sharedworker-module"
-    path_replace = [(".any.sharedworker-module.html", ".any.js", ".any.worker-module.js")]
-    wrapper = """<!doctype html>
-<meta charset=utf-8>
-%(meta)s
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
-<script>
-fetch_tests_from_worker(new SharedWorker("%(path)s%(query)s", { type: "module" }));
-</script>
-"""
-
-
 class ServiceWorkersHandler(HtmlWrapperHandler):
     global_type = "serviceworker"
     path_replace = [(".any.serviceworker.html", ".any.js", ".any.worker.js")]
@@ -327,54 +296,8 @@
 """
 
 
-class ServiceWorkerModulesHandler(HtmlWrapperHandler):
-    global_type = "serviceworker-module"
-    path_replace = [(".any.serviceworker-module.html",
-                     ".any.js", ".any.worker-module.js")]
-    wrapper = """<!doctype html>
-<meta charset=utf-8>
-%(meta)s
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<div id=log></div>
-<script>
-(async function() {
-  const scope = 'does/not/exist';
-  let reg = await navigator.serviceWorker.getRegistration(scope);
-  if (reg) await reg.unregister();
-  reg = await navigator.serviceWorker.register(
-    "%(path)s%(query)s",
-    { scope, type: 'module' },
-  );
-  fetch_tests_from_worker(reg.installing);
-})();
-</script>
-"""
-
-
-class BaseWorkerHandler(WrapperHandler):
+class AnyWorkerHandler(WrapperHandler):
     headers = [('Content-Type', 'text/javascript')]
-
-    def _meta_replacement(self, key, value):
-        return None
-
-    @abc.abstractmethod
-    def _create_script_import(self, attribute):
-        # Take attribute (a string URL to a JS script) and return JS source to import the script
-        # into the worker.
-        pass
-
-    def _script_replacement(self, key, value):
-        if key == "script":
-            attribute = value.replace("\\", "\\\\").replace('"', '\\"')
-            return self._create_script_import(attribute)
-        if key == "title":
-            value = value.replace("\\", "\\\\").replace('"', '\\"')
-            return 'self.META_TITLE = "%s";' % value
-        return None
-
-
-class ClassicWorkerHandler(BaseWorkerHandler):
     path_replace = [(".any.worker.js", ".any.js")]
     wrapper = """%(meta)s
 self.GLOBAL = {
@@ -387,25 +310,17 @@
 done();
 """
 
-    def _create_script_import(self, attribute):
-        return 'importScripts("%s")' % attribute
+    def _meta_replacement(self, key, value):
+        return None
 
-
-class ModuleWorkerHandler(BaseWorkerHandler):
-    path_replace = [(".any.worker-module.js", ".any.js")]
-    wrapper = """%(meta)s
-self.GLOBAL = {
-  isWindow: function() { return false; },
-  isWorker: function() { return true; },
-};
-import "/resources/testharness.js";
-%(script)s
-import "%(path)s";
-done();
-"""
-
-    def _create_script_import(self, attribute):
-        return 'import "%s";' % attribute
+    def _script_replacement(self, key, value):
+        if key == "script":
+            attribute = value.replace("\\", "\\\\").replace('"', '\\"')
+            return 'importScripts("%s")' % attribute
+        if key == "title":
+            value = value.replace("\\", "\\\\").replace('"', '\\"')
+            return 'self.META_TITLE = "%s";' % value
+        return None
 
 
 rewrites = [("GET", "/resources/WebIDLParser.js", "/resources/webidl2/lib/webidl2.js")]
@@ -453,15 +368,11 @@
 
         routes = [
             ("GET", "*.worker.html", WorkersHandler),
-            ("GET", "*.worker-module.html", WorkerModulesHandler),
             ("GET", "*.window.html", WindowHandler),
             ("GET", "*.any.html", AnyHtmlHandler),
             ("GET", "*.any.sharedworker.html", SharedWorkersHandler),
-            ("GET", "*.any.sharedworker-module.html", SharedWorkerModulesHandler),
             ("GET", "*.any.serviceworker.html", ServiceWorkersHandler),
-            ("GET", "*.any.serviceworker-module.html", ServiceWorkerModulesHandler),
-            ("GET", "*.any.worker.js", ClassicWorkerHandler),
-            ("GET", "*.any.worker-module.js", ModuleWorkerHandler),
+            ("GET", "*.any.worker.js", AnyWorkerHandler),
             ("GET", "*.asis", handlers.AsIsHandler),
             ("GET", "/.well-known/origin-policy", handlers.PythonScriptHandler),
             ("*", "*.py", handlers.PythonScriptHandler),
@@ -786,7 +697,7 @@
 def start_ws_server(host, port, paths, routes, bind_address, config, **kwargs):
     # Ensure that when we start this in a new process we have the global lock
     # in the logging module unlocked
-    importlib.reload(logging)
+    reload_module(logging)
     release_mozlog_lock()
     try:
         return WebSocketDaemon(host,
@@ -802,7 +713,7 @@
 def start_wss_server(host, port, paths, routes, bind_address, config, **kwargs):
     # Ensure that when we start this in a new process we have the global lock
     # in the logging module unlocked
-    importlib.reload(logging)
+    reload_module(logging)
     release_mozlog_lock()
     try:
         return WebSocketDaemon(host,
@@ -860,7 +771,7 @@
 def start_quic_transport_server(host, port, paths, routes, bind_address, config, **kwargs):
     # Ensure that when we start this in a new process we have the global lock
     # in the logging module unlocked
-    importlib.reload(logging)
+    reload_module(logging)
     release_mozlog_lock()
     try:
         return QuicTransportDaemon(host,
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
index 0a3bcdb..b075d98 100755
--- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
+++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/standalone.py
@@ -403,7 +403,8 @@
 def _main(args=None):
     """You can call this function from your own program, but please note that
     this function has some side-effects that might affect your program. For
-    example, it changes the current directory.
+    example, util.wrap_popen3_for_win use in this method replaces implementation
+    of os.popen3.
     """
 
     options, args = _parse_args_and_config(args=args)
@@ -426,6 +427,7 @@
             # full path of third_party/cygwin/bin.
             if 'CYGWIN_PATH' in os.environ:
                 cygwin_path = os.environ['CYGWIN_PATH']
+            util.wrap_popen3_for_win(cygwin_path)
 
             def __check_script(scriptpath):
                 return util.get_script_interp(scriptpath, cygwin_path)
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py
index 04006ec..e164e6b8 100644
--- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py
+++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/mod_pywebsocket/util.py
@@ -97,6 +97,25 @@
     return None
 
 
+def wrap_popen3_for_win(cygwin_path):
+    """Wrap popen3 to support #!-script on Windows.
+
+    Args:
+      cygwin_path:  path for cygwin binary if command path is needed to be
+                    translated.  None if no translation required.
+    """
+    __orig_popen3 = os.popen3
+
+    def __wrap_popen3(cmd, mode='t', bufsize=-1):
+        cmdline = cmd.split(' ')
+        interp = get_script_interp(cmdline[0], cygwin_path)
+        if interp:
+            cmd = interp + ' ' + cmd
+        return __orig_popen3(cmd, mode, bufsize)
+
+    os.popen3 = __wrap_popen3
+
+
 def hexify(s):
     return ' '.join(['%02x' % x for x in six.iterbytes(s)])
 
diff --git a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/setup.py b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/setup.py
index b65904c9..57e9428d 100755
--- a/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/setup.py
+++ b/third_party/wpt_tools/wpt/tools/third_party/pywebsocket3/setup.py
@@ -43,7 +43,7 @@
 
 # This is used since python_requires field is not recognized with
 # pip version 9.0.0 and earlier
-if sys.hexversion < 0x020700f0:
+if sys.version < '2.7':
     print('%s requires Python 2.7 or later.' % _PACKAGE_NAME, file=sys.stderr)
     sys.exit(1)
 
@@ -66,8 +66,9 @@
     packages=[_PACKAGE_NAME, _PACKAGE_NAME + '.handshake'],
     python_requires='>=2.7',
     install_requires=['six'],
-    url='https://github.com/GoogleChromeLabs/pywebsocket3',
-    version='3.0.1',
+    #TODO(suzukikeita): Update this to new Github URL
+    url='http://code.google.com/p/pywebsocket/',
+    version='3.0.0',
 )
 
 # vi:sts=4 sw=4 et
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/__init__.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/__init__.py
index a817514..0e1a9de 100644
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/__init__.py
+++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/__init__.py
@@ -35,5 +35,3 @@
     UnknownMethodException,
     UnsupportedOperationException,
     WebDriverException)
-from .bidi import (
-    BidiSession)
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi.py
deleted file mode 100644
index 0bcd489..0000000
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/bidi.py
+++ /dev/null
@@ -1,56 +0,0 @@
-import copy
-import websockets
-
-from . import client
-
-class BidiSession(client.Session):
-    def __init__(self,
-                 host,
-                 port,
-                 url_prefix="/",
-                 capabilities=None,
-                 extension=None):
-        """
-        Add a capability of "webSocketUrl": True to enable
-        Bidirectional connection in session creation.
-        """
-        self.websocket_transport = None
-        capabilities = self._enable_websocket(capabilities)
-        super().__init__(host, port, url_prefix, capabilities, extension)
-
-    def _enable_websocket(self, caps):
-        if caps:
-            caps.setdefault("alwaysMatch", {}).update({"webSocketUrl": True})
-        else:
-            caps = {"alwaysMatch": {"webSocketUrl": True}}
-        return caps
-
-    def match(self, capabilities):
-        """Expensive match to see if capabilities is the same as previously
-        requested capabilities if websocket would be enabled.
-
-        :return Boolean.
-        """
-        caps = copy.deepcopy(capabilities)
-        caps = self._enable_websocket(caps)
-        return super().match(caps)
-
-    async def start(self):
-        """Start a new WebDriver Bidirectional session
-        with websocket connected.
-
-        :return: Dictionary with `capabilities` and `sessionId`.
-        """
-        value = super().start()
-
-        if not self.websocket_transport or not self.websocket_transport.open:
-            self.websocket_transport = await websockets.connect(self.capabilities["webSocketUrl"])
-        return value
-
-    async def end(self):
-        """Close websocket connection first before closing session.
-        """
-        if self.websocket_transport:
-            await self.websocket_transport.close()
-            self.websocket_transport = None
-        super().end()
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/client.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/client.py
index 22533409..19fe336a 100644
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/client.py
+++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/client.py
@@ -2,7 +2,8 @@
 from . import protocol
 from . import transport
 
-from urllib import parse as urlparse
+from six import string_types
+from six.moves.urllib import parse as urlparse
 
 
 def command(func):
@@ -434,7 +435,7 @@
         cookie = {"name": name,
                   "value": None}
 
-        if isinstance(name, str):
+        if isinstance(name, string_types):
             cookie["value"] = value
         elif hasattr(value, "value"):
             cookie["value"] = value.value
@@ -505,9 +506,6 @@
     def __del__(self):
         self.end()
 
-    def match(self, capabilities):
-        return self.requested_capabilities == capabilities
-
     def start(self):
         """Start a new WebDriver session.
 
@@ -755,6 +753,7 @@
     def screenshot(self):
         return self.send_session_command("GET", "screenshot")
 
+
 class Element(object):
     """
     Representation of a web element.
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/error.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/error.py
index 807c592..6426129 100644
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/error.py
+++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/error.py
@@ -1,6 +1,8 @@
 import collections
 import json
 
+from six import itervalues
+
 
 class WebDriverException(Exception):
     http_status = None
@@ -218,6 +220,6 @@
 
 
 _errors = collections.defaultdict()
-for item in list(locals().values()):
+for item in list(itervalues(locals())):
     if type(item) == type and issubclass(item, WebDriverException):
         _errors[item.status_code] = item
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/protocol.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/protocol.py
index e71e01d6..d3faa850 100644
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/protocol.py
+++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/protocol.py
@@ -2,6 +2,8 @@
 
 import webdriver
 
+from six import iteritems
+
 
 """WebDriver wire protocol codecs."""
 
@@ -43,5 +45,5 @@
         elif isinstance(payload, dict) and webdriver.ShadowRoot.identifier in payload:
             return webdriver.ShadowRoot.from_json(payload, self.session)
         elif isinstance(payload, dict):
-            return {k: self.object_hook(v) for k, v in payload.items()}
+            return {k: self.object_hook(v) for k, v in iteritems(payload)}
         return payload
diff --git a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/transport.py b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/transport.py
index 15ba6b8fe..33142d3 100644
--- a/third_party/wpt_tools/wpt/tools/webdriver/webdriver/transport.py
+++ b/third_party/wpt_tools/wpt/tools/webdriver/webdriver/transport.py
@@ -1,9 +1,10 @@
 import json
 import select
 
-from collections.abc import Mapping
-from http.client import HTTPConnection
-from urllib import parse as urlparse
+from six import text_type, PY3
+from six.moves.collections_abc import Mapping
+from six.moves.http_client import HTTPConnection
+from six.moves.urllib import parse as urlparse
 
 from . import error
 
@@ -156,6 +157,8 @@
         """Gets the current HTTP connection, or lazily creates one."""
         if not self._conn:
             conn_kwargs = {}
+            if not PY3:
+                conn_kwargs["strict"] = True
             # We are not setting an HTTP timeout other than the default when the
             # connection its created. The send method has a timeout value if needed.
             self._conn = HTTPConnection(self.host, self.port, **conn_kwargs)
@@ -237,7 +240,7 @@
         return Response.from_http(response, decoder=decoder, **codec_kwargs)
 
     def _request(self, method, uri, payload, headers=None, timeout=None):
-        if isinstance(payload, str):
+        if isinstance(payload, text_type):
             payload = payload.encode("utf-8")
 
         if headers is None:
diff --git a/third_party/wpt_tools/wpt/tools/wpt/android.py b/third_party/wpt_tools/wpt/tools/wpt/android.py
index 8ded6e1..744e134d 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/android.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/android.py
@@ -89,8 +89,8 @@
 
     #TODO: Not sure what's really needed here
     packages = ["platform-tools",
-                "build-tools;30.0.2",
-                "platforms;android-30",
+                "build-tools;29.0.3",
+                "platforms;android-29",
                 "emulator"]
 
     # TODO: make this work non-internactively
diff --git a/third_party/wpt_tools/wpt/tools/wpt/browser.py b/third_party/wpt_tools/wpt/tools/wpt/browser.py
index 2995d52..800080e 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/browser.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/browser.py
@@ -9,7 +9,7 @@
 from datetime import datetime, timedelta
 from distutils.spawn import find_executable
 
-from urllib.parse import urlsplit
+from six.moves.urllib.parse import urlsplit
 import requests
 
 from .utils import call, get, rmtree, untar, unzip, get_download_to_descriptor, sha256sum
diff --git a/third_party/wpt_tools/wpt/tools/wpt/run.py b/third_party/wpt_tools/wpt/tools/wpt/run.py
index 1dcb1d4..68f8e32 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/run.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/run.py
@@ -3,6 +3,7 @@
 import platform
 import sys
 from distutils.spawn import find_executable
+from six.moves import input
 
 wpt_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
 sys.path.insert(0, os.path.abspath(os.path.join(wpt_root, "tools")))
@@ -756,8 +757,9 @@
 
 def setup_wptrunner(venv, **kwargs):
     from wptrunner import wptcommandline
+    from six import iteritems
 
-    kwargs = utils.Kwargs(kwargs.items())
+    kwargs = utils.Kwargs(iteritems(kwargs))
 
     kwargs["product"] = kwargs["product"].replace("-", "_")
 
diff --git a/third_party/wpt_tools/wpt/tools/wpt/testfiles.py b/third_party/wpt_tools/wpt/tools/wpt/testfiles.py
index 5c398588..fee19cd1 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/testfiles.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/testfiles.py
@@ -6,7 +6,7 @@
 import sys
 
 from collections import OrderedDict
-from six import ensure_text, ensure_str
+from six import ensure_text, ensure_str, iteritems
 
 try:
     from ..manifest import manifest
@@ -98,7 +98,7 @@
         branch_point = None
 
         # if there are any commits, take the first parent that is not in commits
-        for commit, parents in commit_parents.items():
+        for commit, parents in iteritems(commit_parents):
             for parent in parents:
                 if parent not in commit_parents:
                     branch_point = parent
@@ -251,7 +251,7 @@
     nontests_changed = set(files_changed)
     wpt_manifest = load_manifest(manifest_path, manifest_update)
 
-    test_types = ["crashtest", "print-reftest", "reftest", "testharness", "wdspec"]
+    test_types = ["crashtest", "testharness", "reftest", "wdspec"]
     support_files = {os.path.join(wpt_root, path)
                      for _, path, _ in wpt_manifest.itertypes("support")}
     wdspec_test_files = {os.path.join(wpt_root, path)
diff --git a/third_party/wpt_tools/wpt/tools/wpt/utils.py b/third_party/wpt_tools/wpt/tools/wpt/utils.py
index 30e9574..61dcda5 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/utils.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/utils.py
@@ -9,7 +9,7 @@
 import zipfile
 from io import BytesIO
 from socket import error as SocketError  # NOQA: N812
-from urllib.request import urlopen
+from six.moves.urllib.request import urlopen
 
 MYPY = False
 if MYPY:
diff --git a/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py b/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py
index 1cfb150..51b97cea 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/virtualenv.py
@@ -55,9 +55,13 @@
 
     @property
     def pip_path(self):
-        path = find_executable("pip3", self.bin_path)
+        if sys.version_info.major >= 3:
+            pip_executable = "pip3"
+        else:
+            pip_executable = "pip2"
+        path = find_executable(pip_executable, self.bin_path)
         if path is None:
-            raise ValueError("pip3 not found")
+            raise ValueError("%s not found" % pip_executable)
         return path
 
     @property
diff --git a/third_party/wpt_tools/wpt/tools/wpt/wpt.py b/third_party/wpt_tools/wpt/tools/wpt/wpt.py
index 1faf7d7..9bc6ce6c 100644
--- a/third_party/wpt_tools/wpt/tools/wpt/wpt.py
+++ b/third_party/wpt_tools/wpt/tools/wpt/wpt.py
@@ -6,6 +6,7 @@
 
 from tools import localpaths  # noqa: F401
 
+from six import iteritems
 from . import virtualenv
 
 
@@ -22,7 +23,7 @@
         base_dir = os.path.dirname(abs_path)
         with open(abs_path, "r") as f:
             data = json.load(f)
-            for command, props in data.items():
+            for command, props in iteritems(data):
                 assert "path" in props
                 assert "script" in props
                 rv[command] = {
@@ -30,6 +31,7 @@
                     "script": props["script"],
                     "parser": props.get("parser"),
                     "parse_known": props.get("parse_known", False),
+                    "py3only": props.get("py3only", False),
                     "help": props.get("help"),
                     "virtualenv": props.get("virtualenv", True),
                     "install": props.get("install", []),
@@ -48,8 +50,12 @@
                         dest="skip_venv_setup",
                         help="Whether to use the virtualenv as-is. Must set --venv as well")
     parser.add_argument("--debug", action="store_true", help="Run the debugger in case of an exception")
+    parser.add_argument("--py3", action="store_true",
+                        help="Run with Python 3 (requires a `python3` binary on the PATH)")
+    parser.add_argument("--py2", action="store_true",
+                        help="Run with Python 2 (requires a `python2` binary on the PATH)")
     subparsers = parser.add_subparsers(dest="command")
-    for command, props in commands.items():
+    for command, props in iteritems(commands):
         subparsers.add_parser(command, help=props["help"], add_help=False)
 
     args, extra = parser.parse_known_args(argv)
@@ -94,7 +100,8 @@
     for command in commands:
         props = commands[command]
 
-        if props["virtualenv"]:
+        if (props["virtualenv"] and
+            (not props["py3only"] or sys.version_info.major == 3)):
             setup_virtualenv(None, False, props)
 
         subparser = import_command('wpt', command, props)[1]
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/requirements.txt b/third_party/wpt_tools/wpt/tools/wptrunner/requirements.txt
index 440a88d..1dd4174 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/requirements.txt
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/requirements.txt
@@ -4,7 +4,7 @@
 mozdebug==0.2
 # Pillow 7 requires Python 3
 pillow==6.2.2; python_version <= '2.7'  # pyup: <7.0
-pillow==8.1.2; python_version >= '3.0'
-urllib3[secure]==1.26.4
+pillow==8.1.0; python_version >= '3.0'
+urllib3[secure]==1.26.2
 requests==2.25.1
 six==1.15.0
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/requirements_safari.txt b/third_party/wpt_tools/wpt/tools/wptrunner/requirements_safari.txt
index 55b474ba9..874980b3 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/requirements_safari.txt
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/requirements_safari.txt
@@ -1,2 +1 @@
 mozprocess==1.2.1
-psutil==5.8.0
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/tox.ini b/third_party/wpt_tools/wpt/tools/wptrunner/tox.ini
index 2b9bca17..b39b5eb 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/tox.ini
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/tox.ini
@@ -2,7 +2,7 @@
 xfail_strict=true
 
 [tox]
-envlist = py38-{base,chrome,edge,firefox,ie,opera,safari,sauce,servo,webkit,webkitgtk_minibrowser,epiphany},{py36,py37}-base
+envlist = py27-{base,chrome,edge,firefox,ie,opera,safari,sauce,servo,webkit,webkitgtk_minibrowser,epiphany},{py35,py36,py37,py38}-base
 skip_missing_interpreters = False
 
 [testenv]
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py
index ec05c76..f68312f 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_weblayer.py
@@ -1,7 +1,9 @@
-from .base import require_arg
+import subprocess
+
+from .base import Browser, ExecutorBrowser, require_arg
 from .base import get_timeout_multiplier   # noqa: F401
 from .chrome import executor_kwargs as chrome_executor_kwargs
-from .chrome_android import ChromeAndroidBrowserBase
+from ..webdriver_server import ChromeDriverServer
 from ..executors.executorwebdriver import (WebDriverTestharnessExecutor,  # noqa: F401
                                            WebDriverRefTestExecutor)  # noqa: F401
 from ..executors.executorchrome import ChromeDriverWdspecExecutor  # noqa: F401
@@ -30,9 +32,7 @@
     return {"binary": kwargs["binary"],
             "device_serial": kwargs["device_serial"],
             "webdriver_binary": kwargs["webdriver_binary"],
-            "webdriver_args": kwargs.get("webdriver_args"),
-            "stackparser_script": kwargs.get("stackparser_script"),
-            "output_directory": kwargs.get("output_directory")}
+            "webdriver_args": kwargs.get("webdriver_args")}
 
 
 def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data,
@@ -74,22 +74,61 @@
     return {"server_host": "127.0.0.1"}
 
 
-class WeblayerShell(ChromeAndroidBrowserBase):
+#TODO: refactor common elements of WeblayerShell and ChromeAndroidBrowser
+class WeblayerShell(Browser):
     """Chrome is backed by chromedriver, which is supplied through
     ``wptrunner.webdriver.ChromeDriverServer``.
     """
 
-    def __init__(self, logger, binary,
-                 webdriver_binary="chromedriver",
-                 remote_queue=None,
+    def __init__(self, logger, binary, webdriver_binary="chromedriver",
                  device_serial=None,
-                 webdriver_args=None,
-                 stackparser_script=None,
-                 output_directory=None):
+                 webdriver_args=None):
         """Creates a new representation of Chrome.  The `binary` argument gives
         the browser binary to use for testing."""
-        super(WeblayerShell, self).__init__(logger,
-                webdriver_binary, remote_queue, device_serial,
-                webdriver_args, stackparser_script, output_directory)
+        Browser.__init__(self, logger)
         self.binary = binary
-        self.wptserver_ports = _wptserve_ports
+        self.device_serial = device_serial
+        self.server = ChromeDriverServer(self.logger,
+                                         binary=webdriver_binary,
+                                         args=webdriver_args)
+        self.setup_adb_reverse()
+
+    def _adb_run(self, args):
+        cmd = ['adb']
+        if self.device_serial:
+            cmd.extend(['-s', self.device_serial])
+        cmd.extend(args)
+        self.logger.info(' '.join(cmd))
+        subprocess.check_call(cmd)
+
+    def setup_adb_reverse(self):
+        self._adb_run(['wait-for-device'])
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+        # "adb reverse" basically forwards network connection from device to
+        # host.
+        for port in _wptserve_ports:
+            self._adb_run(['reverse', 'tcp:%d' % port, 'tcp:%d' % port])
+
+    def start(self, **kwargs):
+        self.server.start(block=False)
+
+    def stop(self, force=False):
+        self.server.stop(force=force)
+
+    def pid(self):
+        return self.server.pid
+
+    def is_alive(self):
+        # TODO(ato): This only indicates the driver is alive,
+        # and doesn't say anything about whether a browser session
+        # is active.
+        return self.server.is_alive()
+
+    def cleanup(self):
+        self.stop()
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+
+    def executor_browser(self):
+        return ExecutorBrowser, {"webdriver_url": self.server.url}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py
index 54dd1281..3cde248b 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/android_webview.py
@@ -1,7 +1,9 @@
-from .base import require_arg
+import subprocess
+
+from .base import Browser, ExecutorBrowser, require_arg
 from .base import get_timeout_multiplier   # noqa: F401
 from .chrome import executor_kwargs as chrome_executor_kwargs
-from .chrome_android import ChromeAndroidBrowserBase
+from ..webdriver_server import ChromeDriverServer
 from ..executors.executorwebdriver import (WebDriverTestharnessExecutor,  # noqa: F401
                                            WebDriverRefTestExecutor)  # noqa: F401
 from ..executors.executorchrome import ChromeDriverWdspecExecutor  # noqa: F401
@@ -30,9 +32,7 @@
     return {"binary": kwargs["binary"],
             "device_serial": kwargs["device_serial"],
             "webdriver_binary": kwargs["webdriver_binary"],
-            "webdriver_args": kwargs.get("webdriver_args"),
-            "stackparser_script": kwargs.get("stackparser_script"),
-            "output_directory": kwargs.get("output_directory")}
+            "webdriver_args": kwargs.get("webdriver_args")}
 
 
 def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data,
@@ -51,11 +51,10 @@
     # Note that for WebView, we launch a test shell and have the test shell use WebView.
     # https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/docs/webview-shell.md
     capabilities["goog:chromeOptions"]["androidPackage"] = \
-        kwargs.get("package_name", "org.chromium.webview_shell")
-    capabilities["goog:chromeOptions"]["androidActivity"] = \
-        "org.chromium.webview_shell.WebPlatformTestsActivity"
-    if kwargs.get("device_serial"):
-        capabilities["goog:chromeOptions"]["androidDeviceSerial"] = kwargs["device_serial"]
+        "org.chromium.webview_shell"
+    capabilities["goog:chromeOptions"]["androidActivity"] = ".WebPlatformTestsActivity"
+    if kwargs.get('device_serial'):
+        capabilities["goog:chromeOptions"]["androidDeviceSerial"] = kwargs['device_serial']
 
     # Workaround: driver.quit() cannot quit SystemWebViewShell.
     executor_kwargs["pause_after_test"] = False
@@ -74,21 +73,61 @@
     return {"server_host": "127.0.0.1"}
 
 
-class SystemWebViewShell(ChromeAndroidBrowserBase):
+#TODO: refactor common elements of SystemWebViewShell and ChromeAndroidBrowser
+class SystemWebViewShell(Browser):
     """Chrome is backed by chromedriver, which is supplied through
     ``wptrunner.webdriver.ChromeDriverServer``.
     """
 
     def __init__(self, logger, binary, webdriver_binary="chromedriver",
-                 remote_queue=None,
                  device_serial=None,
-                 webdriver_args=None,
-                 stackparser_script=None,
-                 output_directory=None):
+                 webdriver_args=None):
         """Creates a new representation of Chrome.  The `binary` argument gives
         the browser binary to use for testing."""
-        super(SystemWebViewShell, self).__init__(logger,
-                webdriver_binary, remote_queue, device_serial,
-                webdriver_args, stackparser_script, output_directory)
+        Browser.__init__(self, logger)
         self.binary = binary
-        self.wptserver_ports = _wptserve_ports
+        self.device_serial = device_serial
+        self.server = ChromeDriverServer(self.logger,
+                                         binary=webdriver_binary,
+                                         args=webdriver_args)
+        self.setup_adb_reverse()
+
+    def _adb_run(self, args):
+        cmd = ['adb']
+        if self.device_serial:
+            cmd.extend(['-s', self.device_serial])
+        cmd.extend(args)
+        self.logger.info(' '.join(cmd))
+        subprocess.check_call(cmd)
+
+    def setup_adb_reverse(self):
+        self._adb_run(['wait-for-device'])
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+        # "adb reverse" basically forwards network connection from device to
+        # host.
+        for port in _wptserve_ports:
+            self._adb_run(['reverse', 'tcp:%d' % port, 'tcp:%d' % port])
+
+    def start(self, **kwargs):
+        self.server.start(block=False)
+
+    def stop(self, force=False):
+        self.server.stop(force=force)
+
+    def pid(self):
+        return self.server.pid
+
+    def is_alive(self):
+        # TODO(ato): This only indicates the driver is alive,
+        # and doesn't say anything about whether a browser session
+        # is active.
+        return self.server.is_alive()
+
+    def cleanup(self):
+        self.stop()
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+
+    def executor_browser(self):
+        return ExecutorBrowser, {"webdriver_url": self.server.url}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py
index f7388ad7..f2205b16 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/base.py
@@ -3,6 +3,7 @@
 import socket
 from abc import ABCMeta, abstractmethod
 from copy import deepcopy
+from six import iteritems
 
 from ..wptcommandline import require_arg  # noqa: F401
 
@@ -162,10 +163,6 @@
         with which it should be instantiated"""
         return ExecutorBrowser, {}
 
-    def maybe_parse_tombstone(self):
-        """Possibly parse tombstones on Android device for Android target"""
-        pass
-
     def check_crash(self, process, test):
         """Check if a crash occured and output any useful information to the
         log. Returns a boolean indicating whether a crash occured."""
@@ -205,5 +202,5 @@
     up the browser from the runner process.
     """
     def __init__(self, **kwargs):
-        for k, v in kwargs.items():
+        for k, v in iteritems(kwargs):
             setattr(self, k, v)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py
index 04ac372..d3e27a9 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome.py
@@ -113,7 +113,7 @@
     """
 
     def __init__(self, logger, binary, webdriver_binary="chromedriver",
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         """Creates a new representation of Chrome.  The `binary` argument gives
         the browser binary to use for testing."""
         Browser.__init__(self, logger)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py
index 7580bed..d7e3e210 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_android.py
@@ -1,4 +1,3 @@
-import mozprocess
 import subprocess
 
 from .base import Browser, ExecutorBrowser, require_arg
@@ -34,9 +33,7 @@
     return {"package_name": kwargs["package_name"],
             "device_serial": kwargs["device_serial"],
             "webdriver_binary": kwargs["webdriver_binary"],
-            "webdriver_args": kwargs.get("webdriver_args"),
-            "stackparser_script": kwargs.get("stackparser_script"),
-            "output_directory": kwargs.get("output_directory")}
+            "webdriver_args": kwargs.get("webdriver_args")}
 
 
 def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data,
@@ -71,80 +68,21 @@
     # allow the use of host-resolver-rules in lieu of modifying /etc/hosts file
     return {"server_host": "127.0.0.1"}
 
-class LogcatRunner(object):
-    def __init__(self, logger, browser, remote_queue):
-        self.logger = logger
-        self.browser = browser
-        self.remote_queue = remote_queue
 
-    def start(self):
-        try:
-            self._run()
-        except KeyboardInterrupt:
-            self.stop()
+class ChromeAndroidBrowser(Browser):
+    """Chrome is backed by chromedriver, which is supplied through
+    ``wptrunner.webdriver.ChromeDriverServer``.
+    """
 
-    def _run(self):
-        try:
-            # TODO: adb logcat -c fail randomly with message
-            # "failed to clear the 'main' log"
-            self.browser.clear_log()
-        except subprocess.CalledProcessError:
-            self.logger.error("Failed to clear logcat buffer")
-
-        self._cmd = self.browser.logcat_cmd()
-        self._proc = mozprocess.ProcessHandler(
-            self._cmd,
-            processOutputLine=self.on_output,
-            storeOutput=False)
-        self._proc.run()
-
-    def _send_message(self, command, *args):
-        try:
-            self.remote_queue.put((command, args))
-        except AssertionError:
-            self.logger.warning("Error when send to remote queue")
-
-    def stop(self, force=False):
-        if self.is_alive():
-            kill_result = self._proc.kill()
-            if force and kill_result != 0:
-                self._proc.kill(9)
-
-    def is_alive(self):
-        return hasattr(self._proc, "proc") and self._proc.poll() is None
-
-    def on_output(self, line):
-        data = {
-            "process": "LOGCAT",
-            "command": "logcat",
-            "data": line
-        }
-        self._send_message("log", "process_output", data)
-
-class ChromeAndroidBrowserBase(Browser):
-    def __init__(self, logger,
-                 webdriver_binary="chromedriver",
-                 remote_queue = None,
-                 device_serial=None,
-                 webdriver_args=None,
-                 stackparser_script=None,
-                 output_directory=None):
-        super(ChromeAndroidBrowserBase, self).__init__(logger)
+    def __init__(self, logger, package_name, webdriver_binary="chromedriver",
+                 device_serial=None, webdriver_args=None):
+        Browser.__init__(self, logger)
+        self.package_name = package_name
         self.device_serial = device_serial
-        self.stackparser_script = stackparser_script
-        self.output_directory = output_directory
-        self.remote_queue = remote_queue
         self.server = ChromeDriverServer(self.logger,
                                          binary=webdriver_binary,
                                          args=webdriver_args)
-        if self.remote_queue is not None:
-            self.logcat_runner = LogcatRunner(self.logger,
-                                          self, self.remote_queue)
-
-    def setup(self):
         self.setup_adb_reverse()
-        if self.remote_queue is not None:
-            self.logcat_runner.start()
 
     def _adb_run(self, args):
         cmd = ['adb']
@@ -154,6 +92,14 @@
         self.logger.info(' '.join(cmd))
         subprocess.check_call(cmd)
 
+    def setup_adb_reverse(self):
+        self._adb_run(['wait-for-device'])
+        self._adb_run(['forward', '--remove-all'])
+        self._adb_run(['reverse', '--remove-all'])
+        # "adb reverse" forwards network connection from device to host.
+        for port in _wptserve_ports:
+            self._adb_run(['reverse', 'tcp:%d' % port, 'tcp:%d' % port])
+
     def start(self, **kwargs):
         self.server.start(block=False)
 
@@ -173,54 +119,6 @@
         self.stop()
         self._adb_run(['forward', '--remove-all'])
         self._adb_run(['reverse', '--remove-all'])
-        if self.remote_queue is not None:
-            self.logcat_runner.stop(force=True)
 
     def executor_browser(self):
         return ExecutorBrowser, {"webdriver_url": self.server.url}
-
-    def clear_log(self):
-        self._adb_run(['logcat', '-c'])
-
-    def logcat_cmd(self):
-        cmd = ['adb']
-        if self.device_serial:
-            cmd.extend(['-s', self.device_serial])
-        cmd.extend(['logcat', '*:D'])
-        return cmd
-
-    def maybe_parse_tombstone(self, logger):
-        if self.stackparser_script:
-            cmd = [self.stackparser_script, "-a", "-w"]
-            if self.device_serial:
-                cmd.extend(["--device", self.device_serial])
-            cmd.extend(["--output-directory", self.output_directory])
-            raw_output = subprocess.check_output(cmd)
-            for line in raw_output.splitlines():
-                logger.process_output("TRACE", line, "logcat")
-
-    def setup_adb_reverse(self):
-        self._adb_run(['wait-for-device'])
-        self._adb_run(['forward', '--remove-all'])
-        self._adb_run(['reverse', '--remove-all'])
-        # "adb reverse" forwards network connection from device to host.
-        for port in self.wptserver_ports:
-            self._adb_run(['reverse', 'tcp:%d' % port, 'tcp:%d' % port])
-
-class ChromeAndroidBrowser(ChromeAndroidBrowserBase):
-    """Chrome is backed by chromedriver, which is supplied through
-    ``wptrunner.webdriver.ChromeDriverServer``.
-    """
-
-    def __init__(self, logger, package_name,
-                 webdriver_binary="chromedriver",
-                 remote_queue = None,
-                 device_serial=None,
-                 webdriver_args=None,
-                 stackparser_script=None,
-                 output_directory=None):
-        super(ChromeAndroidBrowser, self).__init__(logger,
-                webdriver_binary, remote_queue, device_serial,
-                webdriver_args, stackparser_script, output_directory)
-        self.package_name = package_name
-        self.wptserver_ports = _wptserve_ports
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py
index f349b194..ecdbc3a 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_ios.py
@@ -51,7 +51,7 @@
 
     init_timeout = 120
 
-    def __init__(self, logger, webdriver_binary, webdriver_args=None, **kwargs):
+    def __init__(self, logger, webdriver_binary, webdriver_args=None):
         """Creates a new representation of Chrome."""
         Browser.__init__(self, logger)
         self.server = CWTChromeDriverServer(self.logger,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
index 87bbc956..5ee5179 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/chrome_spki_certs.py
@@ -2,7 +2,7 @@
 # DO NOT EDIT MANUALLY.
 
 # tools/certs/web-platform.test.pem
-WPT_FINGERPRINT = 'LjjEE/m/0BKndI/KeccXvPp5wHuXfV09jw9QS7OGIvI='
+WPT_FINGERPRINT = 'OXb4O8pcDI8Nwx3KzqNuTbJ1Znf52VjEVWiYYCjHcIM='
 
 # signed-exchange/resources/127.0.0.1.sxg.pem
 SXG_WPT_FINGERPRINT = '0Rt4mT6SJXojEMHTnKnlJ/hBKMBcI4kteBlhR1eTTdk='
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py
index db4795c..b908684 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edge.py
@@ -68,8 +68,7 @@
     used_ports = set()
     init_timeout = 60
 
-    def __init__(self, logger, webdriver_binary,
-            timeout_multiplier=None, webdriver_args=None, **kwargs):
+    def __init__(self, logger, webdriver_binary, timeout_multiplier=None, webdriver_args=None):
         Browser.__init__(self, logger)
         self.server = EdgeDriverServer(self.logger,
                                        binary=webdriver_binary,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py
index c2275bd1..1d45983 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/edgechromium.py
@@ -85,7 +85,7 @@
     """
 
     def __init__(self, logger, binary, webdriver_binary="msedgedriver",
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         """Creates a new representation of MicrosoftEdge.  The `binary` argument gives
         the browser binary to use for testing."""
         Browser.__init__(self, logger)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py
index f378170f..a338443 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/epiphany.py
@@ -72,6 +72,6 @@
 
 class EpiphanyBrowser(WebKitBrowser):
     def __init__(self, logger, binary=None, webdriver_binary=None,
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         WebKitBrowser.__init__(self, logger, binary, webdriver_binary,
                                webdriver_args)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
index 3a42298..83a883b 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/firefox.py
@@ -196,8 +196,7 @@
           "fission": kwargs.get("enable_fission") or get_bool_pref("fission.autostart"),
           "sessionHistoryInParent": (kwargs.get("enable_fission") or
                                      get_bool_pref("fission.autostart") or
-                                     get_bool_pref("fission.sessionHistoryInParent")),
-          "swgl": get_bool_pref("gfx.webrender.software")}
+                                     get_bool_pref("fission.sessionHistoryInParent"))}
 
     # The value of `sw-e10s` defaults to whether the "parent_intercept"
     # implementation is enabled for the current build. This value, however,
@@ -227,7 +226,7 @@
 
 
 def update_properties():
-    return (["os", "debug", "webrender", "fission", "e10s", "sw-e10s", "processor", "swgl"],
+    return (["os", "debug", "webrender", "fission", "e10s", "sw-e10s", "processor"],
             {"os": ["version"], "processor": ["bits"]})
 
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py
index 5fce29a..3a86c1b6 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/ie.py
@@ -43,7 +43,7 @@
 class InternetExplorerBrowser(Browser):
     used_ports = set()
 
-    def __init__(self, logger, webdriver_binary, webdriver_args=None, **kwargs):
+    def __init__(self, logger, webdriver_binary, webdriver_args=None):
         Browser.__init__(self, logger)
         self.server = InternetExplorerDriverServer(self.logger,
                                                    binary=webdriver_binary,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py
index 80e5a31..a34f419 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/opera.py
@@ -71,7 +71,7 @@
     """
 
     def __init__(self, logger, binary, webdriver_binary="operadriver",
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         """Creates a new representation of Opera.  The `binary` argument gives
         the browser binary to use for testing."""
         Browser.__init__(self, logger)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py
index 9565f1c..312d4db9 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/safari.py
@@ -1,9 +1,3 @@
-import os
-import plistlib
-from distutils.spawn import find_executable
-
-import psutil
-
 from .base import Browser, ExecutorBrowser, require_arg
 from .base import get_timeout_multiplier   # noqa: F401
 from ..webdriver_server import SafariDriverServer
@@ -34,8 +28,7 @@
 
 def browser_kwargs(logger, test_type, run_info_data, config, **kwargs):
     return {"webdriver_binary": kwargs["webdriver_binary"],
-            "webdriver_args": kwargs.get("webdriver_args"),
-            "kill_safari": kwargs.get("kill_safari", False)}
+            "webdriver_args": kwargs.get("webdriver_args")}
 
 
 def executor_kwargs(logger, test_type, server_config, cache_manager, run_info_data,
@@ -65,60 +58,15 @@
     ``wptrunner.webdriver.SafariDriverServer``.
     """
 
-    def __init__(self, logger, webdriver_binary, webdriver_args=None, kill_safari=False, **kwargs):
+    def __init__(self, logger, webdriver_binary, webdriver_args=None):
         """Creates a new representation of Safari.  The `webdriver_binary`
         argument gives the WebDriver binary to use for testing. (The browser
         binary location cannot be specified, as Safari and SafariDriver are
-        coupled.) If `kill_safari` is True, then `Browser.stop` will stop Safari."""
+        coupled.)"""
         Browser.__init__(self, logger)
         self.server = SafariDriverServer(self.logger,
                                          binary=webdriver_binary,
                                          args=webdriver_args)
-        if "/" not in webdriver_binary:
-            wd_path = find_executable(webdriver_binary)
-        else:
-            wd_path = webdriver_binary
-        self.safari_path = self._findAssociatedSafariExecutable(wd_path)
-
-        logger.debug("WebDriver executable path: %s" % wd_path)
-        logger.debug("Safari executable path: %s" % self.safari_path)
-
-        self.kill_safari = kill_safari
-
-    def _findAssociatedSafariExecutable(self, wd_path):
-        bundle_paths = [
-            os.path.join(os.path.dirname(wd_path), "..", ".."),  # bundled Safari (e.g. STP)
-            os.path.join(os.path.dirname(wd_path), "Safari.app"),  # local Safari build
-            "/Applications/Safari.app",  # system Safari
-        ]
-
-        for bundle_path in bundle_paths:
-            info_path = os.path.join(bundle_path, "Contents", "Info.plist")
-            if not os.path.isfile(info_path):
-                continue
-
-            with open(info_path, "rb") as fp:
-                info = plistlib.load(fp)
-
-            # check we have a Safari family bundle
-            if "CFBundleIdentifier" not in info:
-                continue
-            ident = info["CFBundleIdentifier"]
-            if not isinstance(ident, str) or not ident.startswith("com.apple.Safari"):
-                continue
-
-            # get the executable name
-            if "CFBundleExecutable" not in info:
-                continue
-            exe = info["CFBundleExecutable"]
-            if not isinstance(exe, str):
-                continue
-
-            exe_path = os.path.join(bundle_path, "Contents", "MacOS", exe)
-            if not os.path.isfile(exe_path):
-                continue
-
-            return exe_path
 
     def start(self, **kwargs):
         self.server.start(block=False)
@@ -126,20 +74,6 @@
     def stop(self, force=False):
         self.server.stop(force=force)
 
-        if self.kill_safari:
-            self.logger.debug("Going to stop Safari")
-            for proc in psutil.process_iter(attrs=["exe"]):
-                if proc.info["exe"] is not None and os.path.samefile(proc.info["exe"], self.safari_path):
-                    self.logger.debug("Stopping Safari %s" % proc.pid)
-                    try:
-                        proc.terminate()
-                        try:
-                            proc.wait(10)
-                        except psutil.TimeoutExpired:
-                            proc.kill()
-                    except psutil.NoSuchProcess:
-                        pass
-
     def pid(self):
         return self.server.pid
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py
index 99ece89d..3497c5c 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/sauce.py
@@ -12,7 +12,7 @@
 
 import requests
 
-from io import StringIO
+from six.moves import cStringIO as StringIO
 
 from .base import Browser, ExecutorBrowser, require_arg
 from .base import get_timeout_multiplier   # noqa: F401
@@ -228,7 +228,7 @@
 class SauceBrowser(Browser):
     init_timeout = 300
 
-    def __init__(self, logger, sauce_config, **kwargs):
+    def __init__(self, logger, sauce_config):
         Browser.__init__(self, logger)
         self.sauce_config = sauce_config
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py
index 4f934aed..a65ed5ea 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servo.py
@@ -71,7 +71,7 @@
 
 class ServoBrowser(NullBrowser):
     def __init__(self, logger, binary, debug_info=None, binary_args=None,
-                 user_stylesheets=None, ca_certificate_path=None, **kwargs):
+                 user_stylesheets=None, ca_certificate_path=None):
         NullBrowser.__init__(self, logger)
         self.binary = binary
         self.debug_info = debug_info
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py
index 83b9423..ed85cbf 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/servodriver.py
@@ -77,8 +77,7 @@
     init_timeout = 300  # Large timeout for cases where we're booting an Android emulator
 
     def __init__(self, logger, binary, debug_info=None, webdriver_host="127.0.0.1",
-                 server_config=None, binary_args=None,
-                 user_stylesheets=None, headless=None, **kwargs):
+                 server_config=None, binary_args=None, user_stylesheets=None, headless=None):
         Browser.__init__(self, logger)
         self.binary = binary
         self.binary_args = binary_args or []
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py
index f83de29..590e472 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkit.py
@@ -82,7 +82,7 @@
     """
 
     def __init__(self, logger, binary, webdriver_binary=None,
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         Browser.__init__(self, logger)
         self.binary = binary
         self.server = WebKitDriverServer(self.logger, binary=webdriver_binary,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py
index 6c1001e..5b7a360f 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/browsers/webkitgtk_minibrowser.py
@@ -76,6 +76,6 @@
 
 class WebKitGTKMiniBrowser(WebKitBrowser):
     def __init__(self, logger, binary=None, webdriver_binary=None,
-                 webdriver_args=None, **kwargs):
+                 webdriver_args=None):
         WebKitBrowser.__init__(self, logger, binary, webdriver_binary,
                                webdriver_args)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py
index 3f5e934..d46beb8e 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/config.py
@@ -1,4 +1,4 @@
-from configparser import SafeConfigParser
+from six.moves.configparser import SafeConfigParser
 import os
 import sys
 from collections import OrderedDict
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py
index 86dcb93..b68fce05 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/environment.py
@@ -5,6 +5,7 @@
 import socket
 import sys
 import time
+from six import iteritems
 
 from mozlog import get_default_logger, handlers, proxy
 
@@ -107,7 +108,7 @@
     def __exit__(self, exc_type, exc_val, exc_tb):
         self.process_interrupts()
 
-        for scheme, servers in self.servers.items():
+        for scheme, servers in iteritems(self.servers):
             for port, server in servers:
                 server.kill()
         for cm in self.env_extras_cms:
@@ -214,7 +215,7 @@
         route_builder.add_handler("GET", "/resources/testdriver.js",
                                   StringHandler(data, "text/javascript"))
 
-        for url_base, paths in self.test_paths.items():
+        for url_base, paths in iteritems(self.test_paths):
             if url_base == "/":
                 continue
             route_builder.add_mount_point(url_base, paths["tests_path"])
@@ -246,13 +247,13 @@
         failed = []
         pending = []
         host = self.config["server_host"]
-        for scheme, servers in self.servers.items():
+        for scheme, servers in iteritems(self.servers):
             for port, server in servers:
                 if not server.is_alive():
                     failed.append((scheme, port))
 
         if not failed and self.test_server_port:
-            for scheme, servers in self.servers.items():
+            for scheme, servers in iteritems(self.servers):
                 # TODO(Hexcles): Find a way to test QUIC's UDP port.
                 if scheme == "quic-transport":
                     continue
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py
index b47d0ad..1b754219 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -8,8 +8,9 @@
 import socket
 import sys
 from abc import ABCMeta, abstractmethod
-from http.client import HTTPConnection
-from urllib.parse import urljoin, urlsplit, urlunsplit
+from six import text_type
+from six.moves.http_client import HTTPConnection
+from six.moves.urllib.parse import urljoin, urlsplit, urlunsplit
 
 from .actions import actions
 from .protocol import Protocol, BaseProtocolPart
@@ -286,9 +287,9 @@
         """Run a particular test.
 
         :param test: The test to run"""
+        if test.environment != self.last_environment:
+            self.on_environment_change(test.environment)
         try:
-            if test.environment != self.last_environment:
-                self.on_environment_change(test.environment)
             result = self.do_test(test)
         except Exception as e:
             exception_string = traceback.format_exc()
@@ -332,7 +333,7 @@
             status = e.status
         else:
             status = "INTERNAL-ERROR"
-        message = str(getattr(e, "message", ""))
+        message = text_type(getattr(e, "message", ""))
         if message:
             message += "\n"
         message += exception_string
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py
index 431d398..3a70475 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorchrome.py
@@ -1,7 +1,7 @@
 import os
 import traceback
 
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
 
 from .base import WdspecProtocol, WdspecExecutor, get_pages
 from .executorwebdriver import WebDriverProtocol, WebDriverRefTestExecutor, WebDriverRun
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
index 81be731b..d61e1f2 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -5,7 +5,8 @@
 import traceback
 import uuid
 
-from urllib.parse import urljoin
+from six import iteritems, iterkeys
+from six.moves.urllib.parse import urljoin
 
 errors = None
 marionette = None
@@ -726,14 +727,14 @@
 
     def on_environment_change(self, old_environment, new_environment):
         #Unset all the old prefs
-        for name in old_environment.get("prefs", {}).keys():
+        for name in iterkeys(old_environment.get("prefs", {})):
             value = self.executor.original_pref_values[name]
             if value is None:
                 self.prefs.clear(name)
             else:
                 self.prefs.set(name, value)
 
-        for name, value in new_environment.get("prefs", {}).items():
+        for name, value in iteritems(new_environment.get("prefs", {})):
             self.executor.original_pref_values[name] = self.prefs.get(name)
             self.prefs.set(name, value)
 
@@ -999,7 +1000,7 @@
                 result["extra"]["assertion_count"] = assertion_count
 
         if self.debug_test and result["status"] in ["PASS", "FAIL", "ERROR"] and "extra" in result:
-            self.protocol.base.set_window(self.protocol.base.window_handles()[0])
+            self.parent.base.set_window(self.parent.base.window_handles()[0])
             self.protocol.debug.load_reftest_analyzer(test, result)
 
         return self.convert_result(test, result)
@@ -1047,7 +1048,8 @@
         data = {"screenshot": screenshot, "isPrint": self.executor.is_print}
         if self.executor.group_metadata is not None:
             data["urlCount"] = {urljoin(self.executor.server_url(key[0]), key[1]):value
-                                for key, value in self.executor.group_metadata.get("url_count", {}).items()
+                                for key, value in iteritems(
+                                    self.executor.group_metadata.get("url_count", {}))
                                 if value > 1}
         self.chrome_scope = chrome_scope
         if chrome_scope:
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
index 783903b9..6070007 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
@@ -6,7 +6,7 @@
 import time
 import traceback
 import uuid
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
 
 from .base import (CallbackHandler,
                    RefTestExecutor,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorservo.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorservo.py
index 597c879..efe93ab 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorservo.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorservo.py
@@ -7,7 +7,7 @@
 import threading
 import traceback
 import uuid
-from six import ensure_str
+from six import ensure_str, iteritems
 
 from mozprocess import ProcessHandler
 
@@ -48,7 +48,7 @@
         args += ["-Z", debug_opts]
     for stylesheet in browser.user_stylesheets:
         args += ["--user-stylesheet", stylesheet]
-    for pref, value in test.environment.get('prefs', {}).items():
+    for pref, value in iteritems(test.environment.get('prefs', {})):
         args += ["--pref", "%s=%s" % (pref, value)]
     if browser.ca_certificate_path:
         args += ["--certificate-path", browser.ca_certificate_path]
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
index a04a55a..0a968bf3 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -6,7 +6,7 @@
 import time
 import traceback
 import uuid
-from urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin
 
 from .base import (CallbackHandler,
                    CrashtestExecutor,
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py
index ab16b0ef..05e251c 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/executors/protocol.py
@@ -531,7 +531,7 @@
     def load_reftest_analyzer(self, test, result):
         import io
         import mozlog
-        from urllib.parse import quote, urljoin
+        from six.moves.urllib.parse import quote, urljoin
 
         debug_test_logger = mozlog.structuredlog.StructuredLogger("debug_test")
         output = io.StringIO()
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/expectedtree.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/expectedtree.py
index 76ade95f..7521f25 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/expectedtree.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/expectedtree.py
@@ -1,5 +1,6 @@
 from math import log
 from collections import defaultdict
+from six import iteritems, itervalues
 
 class Node(object):
     def __init__(self, prop, value):
@@ -33,7 +34,7 @@
 
     result_counts = defaultdict(int)
     total = float(len(results))
-    for values in results.values():
+    for values in itervalues(results):
         # Not sure this is right, possibly want to treat multiple values as
         # distinct from multiple of the same value?
         for value in values:
@@ -41,7 +42,7 @@
 
     entropy_sum = 0
 
-    for count in result_counts.values():
+    for count in itervalues(result_counts):
         prop = float(count) / total
         entropy_sum -= prop * log(prop, 2)
 
@@ -52,7 +53,7 @@
     """Split a dictionary of results into a dictionary of dictionaries where
     each sub-dictionary has a specific value of the given property"""
     by_prop = defaultdict(dict)
-    for run_info, value in results.items():
+    for run_info, value in iteritems(results):
         by_prop[run_info[prop]][run_info] = value
 
     return by_prop
@@ -77,13 +78,13 @@
     prop_index = {prop: i for i, prop in enumerate(properties)}
 
     all_results = defaultdict(int)
-    for result_values in results.values():
-        for result_value, count in result_values.items():
+    for result_values in itervalues(results):
+        for result_value, count in iteritems(result_values):
             all_results[result_value] += count
 
     # If there is only one result we are done
     if not properties or len(all_results) == 1:
-        for value, count in all_results.items():
+        for value, count in iteritems(all_results):
             tree.result_values[value] += count
         tree.run_info |= set(results.keys())
         return tree
@@ -99,7 +100,7 @@
             continue
         new_entropy = 0.
         results_sets_entropy = []
-        for prop_value, result_set in result_sets.items():
+        for prop_value, result_set in iteritems(result_sets):
             results_sets_entropy.append((entropy(result_set), prop_value, result_set))
             new_entropy += (float(len(result_set)) / len(results)) * results_sets_entropy[-1][0]
 
@@ -109,7 +110,7 @@
 
     # In the case that no properties partition the space
     if not results_partitions:
-        for value, count in all_results.items():
+        for value, count in iteritems(all_results):
             tree.result_values[value] += count
         tree.run_info |= set(results.keys())
         return tree
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
index ae8d96a1..2ff2bd1 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/chromium.py
@@ -1,5 +1,6 @@
 import json
 import time
+import six
 
 from collections import defaultdict
 from mozlog.formatters import base
@@ -87,7 +88,7 @@
         :param str artifact_name: the name of the artifact
         :param str artifact_value: the value of the artifact
         """
-        assert isinstance(artifact_value, str), "artifact_value must be a str"
+        assert isinstance(artifact_value, six.string_types), "artifact_value must be a str"
         if "artifacts" not in cur_dict.keys():
             cur_dict["artifacts"] = defaultdict(list)
         cur_dict["artifacts"][artifact_name].append(artifact_value)
@@ -271,6 +272,5 @@
         return json.dumps(final_result)
 
     def process_output(self, data):
-        cmd = data.get("command", "")
-        if any(c in cmd for c in ["chromedriver", "logcat"]):
+        if 'command' in data and 'chromedriver' in data['command']:
             self.browser_log.append(data['data'])
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
index 53d64df7..55a12b1d7 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/formatters/tests/test_chromium.py
@@ -1,7 +1,7 @@
 import json
 import sys
 from os.path import dirname, join
-from io import StringIO
+from six.moves import cStringIO as StringIO
 
 from mozlog import handlers, structuredlog
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/instruments.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/instruments.py
index 4e3e013..a887cf4 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/instruments.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/instruments.py
@@ -1,6 +1,6 @@
 import time
 import threading
-from queue import Queue
+from six.moves.queue import Queue
 
 """Instrumentation for measuring high-level time spent on various tasks inside the runner.
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestexpected.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestexpected.py
index 2f7f533..31c57e9 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestexpected.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestexpected.py
@@ -1,6 +1,8 @@
 import os
 from collections import deque
-from urllib.parse import urljoin
+from six import string_types, text_type
+from six.moves.urllib.parse import urljoin
+
 
 from .wptmanifest.backends import static
 from .wptmanifest.backends.base import ManifestItem
@@ -47,7 +49,7 @@
     """List property"""
     try:
         list_prop = node.get(name)
-        if isinstance(list_prop, str):
+        if isinstance(list_prop, string_types):
             return [list_prop]
         return list(list_prop)
     except KeyError:
@@ -57,7 +59,7 @@
 def str_prop(name, node):
     try:
         prop = node.get(name)
-        if not isinstance(prop, str):
+        if not isinstance(prop, string_types):
             raise ValueError
         return prop
     except KeyError:
@@ -68,7 +70,7 @@
     """Set of tags that have been applied to the test"""
     try:
         value = node.get("tags")
-        if isinstance(value, str):
+        if isinstance(value, text_type):
             return {value}
         return set(value)
     except KeyError:
@@ -77,7 +79,7 @@
 
 def prefs(node):
     def value(ini_value):
-        if isinstance(ini_value, str):
+        if isinstance(ini_value, text_type):
             return tuple(pref_piece.strip() for pref_piece in ini_value.split(':', 1))
         else:
             # this should be things like @Reset, which are apparently type 'object'
@@ -85,7 +87,7 @@
 
     try:
         node_prefs = node.get("prefs")
-        if isinstance(node_prefs, str):
+        if isinstance(node_prefs, text_type):
             rv = dict(value(node_prefs))
         else:
             rv = dict(value(item) for item in node_prefs)
@@ -97,7 +99,7 @@
 def set_prop(name, node):
     try:
         node_items = node.get(name)
-        if isinstance(node_items, str):
+        if isinstance(node_items, text_type):
             rv = {node_items}
         else:
             rv = set(node_items)
@@ -110,7 +112,7 @@
     rv = {}
     try:
         node_items = node.get("leak-threshold")
-        if isinstance(node_items, str):
+        if isinstance(node_items, text_type):
             node_items = [node_items]
         for item in node_items:
             process, value = item.rsplit(":", 1)
@@ -167,7 +169,7 @@
     if not isinstance(value, list):
         value = [value]
     for item in value:
-        if not isinstance(item, str):
+        if not isinstance(item, text_type):
             rv.append(item)
             continue
         parts = item.rsplit(":", 1)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestinclude.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestinclude.py
index 97348e6d..79b5b19 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestinclude.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestinclude.py
@@ -6,7 +6,8 @@
 """
 import glob
 import os
-from urllib.parse import urlparse, urlsplit
+from six import iteritems
+from six.moves.urllib.parse import urlparse, urlsplit
 
 from .wptmanifest.node import DataNode
 from .wptmanifest.backends import conditional
@@ -94,7 +95,7 @@
         if paths:
             urls = []
             for path in paths:
-                for manifest, data in test_manifests.items():
+                for manifest, data in iteritems(test_manifests):
                     found = False
                     rel_path = os.path.relpath(path, data["tests_path"])
                     iterator = manifest.iterpath if os.path.isfile(path) else manifest.iterdir
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py
index 5bccaa2d..c74632b0 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/manifestupdate.py
@@ -1,8 +1,9 @@
 from __future__ import print_function
 import os
-from urllib.parse import urljoin, urlsplit
+from six.moves.urllib.parse import urljoin, urlsplit
 from collections import namedtuple, defaultdict, deque
 from math import ceil
+from six import integer_types, iterkeys, itervalues, iteritems, string_types, text_type
 
 from .wptmanifest import serialize
 from .wptmanifest.node import (DataNode, ConditionalNode, BinaryExpressionNode,
@@ -75,7 +76,7 @@
         return name in self._classes
 
     def __iter__(self):
-        for name in self._classes.keys():
+        for name in iterkeys(self._classes):
             yield getattr(self, name)
 
 
@@ -312,8 +313,8 @@
 
 def build_unconditional_tree(_, run_info_properties, results):
     root = expectedtree.Node(None, None)
-    for run_info, values in results.items():
-        for value, count in values.items():
+    for run_info, values in iteritems(results):
+        for value, count in iteritems(values):
             root.result_values[value] += count
         root.run_info.add(run_info)
     return root
@@ -410,7 +411,7 @@
         for e in errors:
             if disable_intermittent:
                 condition = e.cond.children[0] if e.cond else None
-                msg = disable_intermittent if isinstance(disable_intermittent, str) else "unstable"
+                msg = disable_intermittent if isinstance(disable_intermittent, string_types+(text_type,)) else "unstable"
                 self.node.set("disabled", msg, condition)
                 self.node.new_disabled = True
             else:
@@ -498,7 +499,7 @@
                           for run_info in node.run_info}
 
         node_by_run_info = {run_info: node
-                            for (run_info, node) in run_info_index.items()
+                            for (run_info, node) in iteritems(run_info_index)
                             if node.result_values}
 
         run_info_by_condition = self.run_info_by_condition(run_info_index,
@@ -511,7 +512,7 @@
             # using the properties we've specified and not matching any run_info
             top_level_props, dependent_props = self.node.root.run_info_properties
             update_properties = set(top_level_props)
-            for item in dependent_props.values():
+            for item in itervalues(dependent_props):
                 update_properties |= set(item)
             for condition in current_conditions:
                 if ((not condition.variables.issubset(update_properties) and
@@ -694,7 +695,7 @@
             raise ConditionError
 
         counts = {}
-        for status, count in new.items():
+        for status, count in iteritems(new):
             if isinstance(status, tuple):
                 counts[status[0]] = count
                 counts.update({intermittent: 0 for intermittent in status[1:] if intermittent not in counts})
@@ -708,9 +709,9 @@
         # Counts with 0 are considered intermittent.
         statuses = ["OK", "PASS", "FAIL", "ERROR", "TIMEOUT", "CRASH"]
         status_priority = {value: i for i, value in enumerate(statuses)}
-        sorted_new = sorted(counts.items(), key=lambda x:(-1 * x[1],
-                                                        status_priority.get(x[0],
-                                                        len(status_priority))))
+        sorted_new = sorted(iteritems(counts), key=lambda x:(-1 * x[1],
+                                                           status_priority.get(x[0],
+                                                           len(status_priority))))
         expected = []
         for status, count in sorted_new:
             # If we are not removing existing recorded intermittents, with a count of 0,
@@ -776,7 +777,7 @@
         for item in new:
             if item is None:
                 continue
-            elif isinstance(item, str):
+            elif isinstance(item, text_type):
                 rv.add(item)
             else:
                 rv |= item
@@ -824,7 +825,7 @@
         return result
 
     def to_ini_value(self, data):
-        return ["%s:%s" % item for item in sorted(data.items())]
+        return ["%s:%s" % item for item in sorted(iteritems(data))]
 
     def from_ini_value(self, data):
         rv = {}
@@ -899,10 +900,10 @@
 
 
 def make_node(value):
-    if isinstance(value, (int, float,)):
+    if isinstance(value, integer_types+(float,)):
         node = NumberNode(value)
-    elif isinstance(value, str):
-        node = StringNode(str(value))
+    elif isinstance(value, text_type):
+        node = StringNode(text_type(value))
     elif hasattr(value, "__iter__"):
         node = ListNode()
         for item in value:
@@ -911,10 +912,10 @@
 
 
 def make_value_node(value):
-    if isinstance(value, (int, float,)):
+    if isinstance(value, integer_types+(float,)):
         node = ValueNode(value)
-    elif isinstance(value, str):
-        node = ValueNode(str(value))
+    elif isinstance(value, text_type):
+        node = ValueNode(text_type(value))
     elif hasattr(value, "__iter__"):
         node = ListNode()
         for item in value:
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py
index ddc433d..ab8d4740 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/metadata.py
@@ -5,8 +5,8 @@
 from collections import defaultdict, namedtuple
 
 from mozlog import structuredlog
-from six import ensure_str, ensure_text
-from sys import intern
+from six import ensure_str, ensure_text, iteritems, iterkeys, itervalues, text_type
+from six.moves import intern, range
 
 from . import manifestupdate
 from . import testloader
@@ -45,11 +45,11 @@
         return self.canonical_repr == other.canonical_repr
 
     def iteritems(self):
-        for key, value in self.data.items():
+        for key, value in iteritems(self.data):
             yield key, value
 
     def items(self):
-        return list(self.items())
+        return list(iteritems(self))
 
 
 def update_expected(test_paths, serve_root, log_file_names,
@@ -129,7 +129,7 @@
     files_changed = set(files_changed)
 
     root_manifest = None
-    for manifest, paths in manifests.items():
+    for manifest, paths in iteritems(manifests):
         if paths["url_base"] == "/":
             root_manifest = manifest
             break
@@ -240,7 +240,7 @@
 def unpack_result(data):
     if isinstance(data, int):
         return (status_intern.get(data), None)
-    if isinstance(data, str):
+    if isinstance(data, text_type):
         return (data, None)
     # Unpack multiple statuses into a tuple to be used in the Results named tuple below,
     # separating `status` and `known_intermittent`.
@@ -259,7 +259,7 @@
     manifests = manifest_loader.load()
 
     id_test_map = {}
-    for test_manifest, paths in manifests.items():
+    for test_manifest, paths in iteritems(manifests):
         id_test_map.update(create_test_tree(paths["metadata_path"],
                                             test_manifest))
     return id_test_map
@@ -287,10 +287,10 @@
                    disable_intermittent,
                    update_intermittent,
                    remove_intermittent):
-    test_file_items = set(id_test_map.values())
+    test_file_items = set(itervalues(id_test_map))
 
     default_expected_by_type = {}
-    for test_type, test_cls in wpttest.manifest_test_cls.items():
+    for test_type, test_cls in iteritems(wpttest.manifest_test_cls):
         if test_cls.result_cls:
             default_expected_by_type[(test_type, False)] = test_cls.result_cls.default_expected
         if test_cls.subtest_result_cls:
@@ -431,7 +431,7 @@
             action_map["lsan_leak"](item)
 
         mozleak_data = data.get("mozleak", {})
-        for scope, scope_data in mozleak_data.items():
+        for scope, scope_data in iteritems(mozleak_data):
             for key, action in [("objects", "mozleak_object"),
                                 ("total", "mozleak_total")]:
                 for item in scope_data.get(key, []):
@@ -668,11 +668,11 @@
         # Return subtest nodes present in the expected file, but missing from the data
         rv = []
 
-        for test_id, subtests in self.data.items():
+        for test_id, subtests in iteritems(self.data):
             test = expected.get_test(ensure_text(test_id))
             if not test:
                 continue
-            seen_subtests = set(ensure_text(item) for item in subtests.keys() if item is not None)
+            seen_subtests = set(ensure_text(item) for item in iterkeys(subtests) if item is not None)
             missing_subtests = set(test.subtests.keys()) - seen_subtests
             for item in missing_subtests:
                 expected_subtest = test.get_subtest(item)
@@ -691,7 +691,7 @@
         # since removing these may be inappropriate
         top_level_props, dependent_props = update_properties
         all_properties = set(top_level_props)
-        for item in dependent_props.values():
+        for item in itervalues(dependent_props):
             all_properties |= set(item)
 
         filtered = []
@@ -741,9 +741,9 @@
             test_expected = expected.get_test(test_id)
             expected_by_test[test_id] = test_expected
 
-        for test_id, test_data in self.data.items():
+        for test_id, test_data in iteritems(self.data):
             test_id = ensure_str(test_id)
-            for subtest_id, results_list in test_data.items():
+            for subtest_id, results_list in iteritems(test_data):
                 for prop, run_info, value in results_list:
                     # Special case directory metadata
                     if subtest_id is None and test_id.endswith("__dir__"):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/mpcontext.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/mpcontext.py
index a50c0478..daade10 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/mpcontext.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/mpcontext.py
@@ -1,11 +1,21 @@
 import multiprocessing
 
+import six
+
 _context = None
 
 
+class MpContext(object):
+    def __getattr__(self, name):
+        return getattr(multiprocessing, name)
+
+
 def get_context():
     global _context
 
     if _context is None:
-        _context = multiprocessing.get_context("spawn")
+        if six.PY2:
+            _context = MpContext()
+        else:
+            _context = multiprocessing.get_context("spawn")
     return _context
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/process.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/process.py
index d3ff380a..8a2b894 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/process.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/process.py
@@ -1,8 +1,11 @@
+import sys
+
 import six
 
 
 def cast_env(env):
-    """Encode all the environment values as the appropriate type.
+    """Encode all the environment values as the appropriate type for each Python version
     This assumes that all the data is or can be represented as UTF8"""
 
-    return {six.ensure_str(key): six.ensure_str(value) for key, value in env.items()}
+    env_type = six.ensure_binary if sys.version_info[0] < 3 else six.ensure_str
+    return {env_type(key): env_type(value) for key, value in six.iteritems(env)}
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
index 7ba30537..abd8409 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
@@ -1,5 +1,6 @@
 import importlib
 import imp
+from six import iteritems
 
 from .browsers import product_list
 
@@ -44,7 +45,7 @@
         self.get_timeout_multiplier = getattr(module, data["timeout_multiplier"])
 
         self.executor_classes = {}
-        for test_type, cls_name in data["executor"].items():
+        for test_type, cls_name in iteritems(data["executor"]):
             cls = getattr(module, cls_name)
             self.executor_classes[test_type] = cls
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
index 2265523..88d1c23 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
@@ -5,6 +5,7 @@
 import os
 from collections import OrderedDict, defaultdict
 from datetime import datetime
+from six import iteritems
 
 from mozlog import reader
 from mozlog.formatters import JSONFormatter
@@ -141,10 +142,10 @@
     handler = LogHandler()
     reader.handle_log(reader.read(log), handler)
     results = handler.results
-    for test_name, test in results.items():
+    for test_name, test in iteritems(results):
         if is_inconsistent(test["status"], iterations):
             inconsistent.append((test_name, None, test["status"], []))
-        for subtest_name, subtest in test["subtests"].items():
+        for subtest_name, subtest in iteritems(test["subtests"]):
             if is_inconsistent(subtest["status"], iterations):
                 inconsistent.append((test_name, subtest_name, subtest["status"], subtest["messages"]))
 
@@ -234,7 +235,7 @@
                                                   "tests" if len(results) > 1
                                                   else "test"))
 
-    for test_name, test in results.items():
+    for test_name, test in iteritems(results):
         baseurl = "http://w3c-test.org/submissions"
         if "https" in os.path.splitext(test_name)[0].split(".")[1:]:
             baseurl = "https://w3c-test.org/submissions"
@@ -304,7 +305,7 @@
     for kwargs_extra in kwargs_extras:
         if kwargs_extra:
             flags_string = " with flags %s" % " ".join(
-                "%s=%s" % item for item in kwargs_extra.items())
+                "%s=%s" % item for item in iteritems(kwargs_extra))
         else:
             flags_string = ""
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py
index 346fe2a2..e57619b4 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testloader.py
@@ -1,11 +1,12 @@
 import hashlib
 import json
 import os
-from urllib.parse import urlsplit
+from six.moves.urllib.parse import urlsplit
 from abc import ABCMeta, abstractmethod
-from queue import Empty
+from six.moves.queue import Empty
 from collections import defaultdict, deque
-from six import ensure_binary
+from six import ensure_binary, iteritems
+from six.moves import range
 
 from . import manifestinclude
 from . import manifestexpected
@@ -40,7 +41,7 @@
             raise
 
         self.group_by_test = {}
-        for group, test_ids in self._data.items():
+        for group, test_ids in iteritems(self._data):
             for test_id in test_ids:
                 self.group_by_test[test_id] = group
 
@@ -50,16 +51,6 @@
     def __getitem__(self, key):
         return self._data[key]
 
-def read_include_from_file(file):
-    new_include = []
-    with open(file) as f:
-        for line in f:
-            line = line.strip()
-            # Allow whole-line comments;
-            # fragments mean we can't have partial line #-based comments
-            if len(line) > 0 and not line.startswith("#"):
-                new_include.append(line)
-    return new_include
 
 def update_include_for_groups(test_groups, include):
     if include is None:
@@ -182,7 +173,7 @@
 
     def load(self):
         rv = {}
-        for url_base, paths in self.test_paths.items():
+        for url_base, paths in iteritems(self.test_paths):
             manifest_file = self.load_manifest(url_base=url_base,
                                                **paths)
             path_data = {"url_base": url_base}
@@ -481,7 +472,7 @@
         mp = mpcontext.get_context()
         test_queue = mp.Queue()
 
-        for group_name, test_ids in tests_by_group.items():
+        for group_name, test_ids in iteritems(tests_by_group):
             group_metadata = {"scope": group_name}
             group = deque()
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py
index 04221cb..8dd9341 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/testrunner.py
@@ -2,7 +2,7 @@
 
 import threading
 import traceback
-from queue import Empty
+from six.moves.queue import Empty
 from collections import namedtuple
 
 from mozlog import structuredlog, capture
@@ -339,7 +339,6 @@
 
         self.test_count = 0
         self.unexpected_count = 0
-        self.unexpected_pass_count = 0
 
         # This may not really be what we want
         self.daemon = True
@@ -362,8 +361,7 @@
         spins."""
         self.recording.set(["testrunner", "startup"])
         self.logger = structuredlog.StructuredLogger(self.suite_name)
-        with self.browser_cls(self.logger, remote_queue=self.command_queue,
-                              **self.browser_kwargs) as browser:
+        with self.browser_cls(self.logger, **self.browser_kwargs) as browser:
             self.browser = BrowserManager(self.logger,
                                           browser,
                                           self.command_queue,
@@ -616,9 +614,6 @@
             return
         if self.timer is not None:
             self.timer.cancel()
-
-        self.browser.browser.maybe_parse_tombstone()
-
         # Write the result of each subtest
         file_result, test_results = results
         subtest_unexpected = False
@@ -639,11 +634,6 @@
                 self.unexpected_count += 1
                 self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count)
                 subtest_unexpected = True
-
-            is_unexpected_pass = is_unexpected and result.status == "PASS"
-            if is_unexpected_pass:
-                self.unexpected_pass_count += 1
-
             self.logger.test_status(test.id,
                                     result.name,
                                     result.status,
@@ -677,10 +667,6 @@
             self.unexpected_count += 1
             self.logger.debug("Unexpected count in this thread %i" % self.unexpected_count)
 
-        is_unexpected_pass = is_unexpected and status == "OK"
-        if is_unexpected_pass:
-            self.unexpected_pass_count += 1
-
         if "assertion_count" in file_result.extra:
             assertion_count = file_result.extra["assertion_count"]
             if assertion_count is not None and assertion_count > 0:
@@ -789,19 +775,14 @@
             # This might leak a file handle from the queue
             self.logger.warning("Forcibly terminating runner process")
             self.test_runner_proc.terminate()
-            self.logger.debug("After terminating runner process")
 
             # Multiprocessing queues are backed by operating system pipes. If
             # the pipe in the child process had buffered data at the time of
             # forced termination, the queue is no longer in a usable state
             # (subsequent attempts to retrieve items may block indefinitely).
             # Discard the potentially-corrupted queue and create a new one.
-            self.logger.debug("Recreating command queue")
-            self.command_queue.cancel_join_thread()
             self.command_queue.close()
             self.command_queue = mp.Queue()
-            self.logger.debug("Recreating remote queue")
-            self.remote_queue.cancel_join_thread()
             self.remote_queue.close()
             self.remote_queue = mp.Queue()
         else:
@@ -944,6 +925,3 @@
 
     def unexpected_count(self):
         return sum(manager.unexpected_count for manager in self.pool)
-
-    def unexpected_pass_count(self):
-        return sum(manager.unexpected_pass_count for manager in self.pool)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/state.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/state.py
index a526c24..6b6ff1a 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/state.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/state.py
@@ -1,5 +1,5 @@
 import os
-import pickle
+from six.moves import cPickle as pickle  # noqa: N813
 
 here = os.path.abspath(os.path.dirname(__file__))
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py
index 4ace28f..f878752 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/sync.py
@@ -67,7 +67,7 @@
                          state.local_branch)
         sync_path = os.path.abspath(sync_tree.root)
         if sync_path not in sys.path:
-            from .update import setup_paths
+            from update import setup_paths
             setup_paths(sync_path)
 
     def restore(self, state):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/tree.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/tree.py
index 2f43bac..f362770 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/tree.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/tree.py
@@ -3,6 +3,8 @@
 import subprocess
 import tempfile
 
+from six.moves import range
+
 from .. import vcs
 from ..vcs import git, hg
 
@@ -85,7 +87,7 @@
 
     @property
     def is_clean(self):
-        return self.hg("status").strip() == b""
+        return self.hg("status").strip() == ""
 
     def add_new(self, prefix=None):
         if prefix is not None:
@@ -103,7 +105,7 @@
         except subprocess.CalledProcessError:
             pass
 
-        patch_names = [item.strip() for item in self.hg("qseries").split(b"\n") if item.strip()]
+        patch_names = [item.strip() for item in self.hg("qseries").split("\n") if item.strip()]
 
         suffix = 0
         test_name = patch_name
@@ -140,7 +142,7 @@
 
     def __init__(self, root=None, log_error=True):
         if root is None:
-            root = git("rev-parse", "--show-toplevel", log_error=log_error).strip().decode('utf-8')
+            root = git("rev-parse", "--show-toplevel", log_error=log_error).strip()
         self.root = root
         self.git = vcs.bind_to_repo(git, self.root, log_error=log_error)
         self.message = None
@@ -176,7 +178,7 @@
 
     @property
     def is_clean(self):
-        return self.git("status").strip() == b""
+        return self.git("status").strip() == ""
 
     def add_new(self, prefix=None):
         """Add files to the staging area.
@@ -201,7 +203,7 @@
             f.seek(0)
             ignored_files = sync_tree.git("check-ignore", "--no-index", "--stdin", "-z", stdin=f)
         args = []
-        for entry in ignored_files.decode('utf-8').split('\0'):
+        for entry in ignored_files.split('\0'):
             args.append(os.path.join(prefix, entry))
         if args:
             self.git("add", "--force", *args)
@@ -217,7 +219,7 @@
             args.append(ref_filter)
         data = self.git("show-ref", *args)
         rv = []
-        for line in data.split(b"\n"):
+        for line in data.split("\n"):
             if not line.strip():
                 continue
             sha1, ref = line.split()
@@ -235,7 +237,7 @@
             args.append(ref_filter)
         data = self.git("ls-remote", remote, *args)
         rv = []
-        for line in data.split(b"\n"):
+        for line in data.split("\n"):
             if not line.strip():
                 continue
             sha1, ref = line.split()
@@ -248,8 +250,8 @@
         :param remote: the remote URL
         :param branch: the branch name"""
         for sha1, ref in self.list_remote(remote, branch):
-            if ref.decode('utf-8') == "refs/heads/%s" % branch:
-                return self.commit_cls(self, sha1.decode('utf-8'))
+            if ref == "refs/heads/%s" % branch:
+                return self.commit_cls(self, sha1)
         assert False
 
     def create_patch(self, patch_name, message):
@@ -297,8 +299,8 @@
 
         args = []
         if branch:
-            branches = [ref[len("refs/heads/"):].decode('utf-8') for sha1, ref in self.list_refs()
-                        if ref.startswith(b"refs/heads/")]
+            branches = [ref[len("refs/heads/"):] for sha1, ref in self.list_refs()
+                        if ref.startswith("refs/heads/")]
             branch = get_unique_name(branches, branch)
 
             args += ["-b", branch]
@@ -334,8 +336,8 @@
         rv = []
 
         for repo_path in repo_paths:
-            paths = vcs.git("ls-tree", "-r", "--name-only", "HEAD", repo=repo_path).split(b"\n")
-            rv.extend(os.path.relpath(os.path.join(repo_path, item.decode('utf-8')), self.root) for item in paths
+            paths = vcs.git("ls-tree", "-r", "--name-only", "HEAD", repo=repo_path).split("\n")
+            rv.extend(os.path.relpath(os.path.join(repo_path, item), self.root) for item in paths
                       if item.strip())
         return rv
 
@@ -343,11 +345,11 @@
         """List submodule directories"""
         output = self.git("submodule", "status", "--recursive")
         rv = []
-        for line in output.split(b"\n"):
+        for line in output.split("\n"):
             line = line.strip()
             if not line:
                 continue
-            parts = line.split(b" ")
+            parts = line.split(" ")
             rv.append(parts[1])
         return rv
 
@@ -401,5 +403,5 @@
         self.git = self.tree.git
 
     def _get_meta(self):
-        author, email, message = self.git("show", "-s", "--format=format:%an\n%ae\n%B", self.sha1).decode('utf-8').split("\n", 2)
+        author, email, message = self.git("show", "-s", "--format=format:%an\n%ae\n%B", self.sha1).split("\n", 2)
         return author, email, self.msg_cls(message)
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/update.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/update.py
index 265a331..80e509d 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/update.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/update/update.py
@@ -1,6 +1,8 @@
 import os
 import sys
 
+from six import itervalues
+
 from .metadata import MetadataUpdateRunner
 from .sync import SyncFromUpstreamRunner
 from .tree import GitTree, HgTree, NoVCSTree
@@ -109,7 +111,7 @@
         state.tests_path = state.paths["/"]["tests_path"]
         state.metadata_path = state.paths["/"]["metadata_path"]
 
-        for url_paths in paths.values():
+        for url_paths in itervalues(paths):
             tests_path = url_paths["tests_path"]
             metadata_path = url_paths["metadata_path"]
             for dirpath, dirnames, filenames in os.walk(metadata_path):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
index 90edd64..2b6d4b35 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptcommandline.py
@@ -5,7 +5,7 @@
 from collections import OrderedDict
 from distutils.spawn import find_executable
 from datetime import timedelta
-from six import ensure_text
+from six import ensure_text, iterkeys, itervalues, iteritems
 
 from . import config
 from . import wpttest
@@ -16,7 +16,7 @@
 
 
 def url_or_path(path):
-    from urllib.parse import urlparse
+    from six.moves.urllib.parse import urlparse
 
     parsed = urlparse(path)
     if len(parsed.scheme) > 2:
@@ -72,10 +72,6 @@
                         default=True,
                         dest="fail_on_unexpected",
                         help="Exit with status code 0 when test expectations are violated")
-    parser.add_argument("--no-fail-on-unexpected-pass", action="store_false",
-                        default=True,
-                        dest="fail_on_unexpected_pass",
-                        help="Exit with status code 0 when all unexpected results are PASS")
 
     mode_group = parser.add_argument_group("Mode")
     mode_group.add_argument("--list-test-groups", action="store_true",
@@ -135,8 +131,6 @@
                                       help="Test types to run")
     test_selection_group.add_argument("--include", action="append",
                                       help="URL prefix to include")
-    test_selection_group.add_argument("--include-file", action="store",
-                                      help="A file listing URL prefix for tests")
     test_selection_group.add_argument("--exclude", action="append",
                                       help="URL prefix to exclude")
     test_selection_group.add_argument("--include-manifest", type=abs_path,
@@ -189,10 +183,7 @@
                                  help="Path or url to symbols file used to analyse crash minidumps.")
     debugging_group.add_argument("--stackwalk-binary", action="store", type=abs_path,
                                  help="Path to stackwalker program used to analyse minidumps.")
-    debugging_group.add_argument("--output-directory", action="store",
-                                 help="Path to chromium output directory.")
-    debugging_group.add_argument("--stackparser-script", action="store", type=abs_path,
-                                 help="Path to stack parser script used to analyse tombstones.")
+
     debugging_group.add_argument("--pdb", action="store_true",
                                  help="Drop into pdb on python exception")
 
@@ -376,10 +367,6 @@
     webkit_group.add_argument("--webkit-port", dest="webkit_port",
                               help="WebKit port")
 
-    safari_group = parser.add_argument_group("Safari-specific")
-    safari_group.add_argument("--kill-safari", dest="kill_safari", action="store_true", default=False,
-                              help="Kill Safari when stopping the browser")
-
     parser.add_argument("test_list", nargs="*",
                         help="List of URLs for tests to run, or paths including tests to run. "
                              "(equivalent to --include)")
@@ -421,7 +408,7 @@
                     ("host_cert_path", "host_cert_path", True),
                     ("host_key_path", "host_key_path", True)]}
 
-    for section, values in keys.items():
+    for section, values in iteritems(keys):
         for config_value, kw_value, is_path in values:
             if kw_value in kwargs and kwargs[kw_value] is None:
                 if not is_path:
@@ -457,7 +444,7 @@
     # Set up test_paths
     test_paths = OrderedDict()
 
-    for section in config.keys():
+    for section in iterkeys(config):
         if section.startswith("manifest:"):
             manifest_opts = config.get(section)
             url_base = manifest_opts.get("url_base", "/")
@@ -483,7 +470,7 @@
 
 
 def check_paths(kwargs):
-    for test_paths in kwargs["test_paths"].values():
+    for test_paths in itervalues(kwargs["test_paths"]):
         if not ("tests_path" in test_paths and
                 "metadata_path" in test_paths):
             print("Fatal: must specify both a test path and metadata path")
@@ -491,7 +478,7 @@
         if "manifest_path" not in test_paths:
             test_paths["manifest_path"] = os.path.join(test_paths["metadata_path"],
                                                        "MANIFEST.json")
-        for key, path in test_paths.items():
+        for key, path in iteritems(test_paths):
             name = key.split("_", 1)[0]
 
             if name == "manifest":
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/base.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/base.py
index 3069e4c..c539d43 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/base.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/base.py
@@ -1,4 +1,5 @@
 import abc
+from six import iteritems, iterkeys, itervalues
 
 from ..node import NodeVisitor
 from ..parser import parse
@@ -186,21 +187,21 @@
     def _flatten(self):
         rv = {}
         for node in [self, self.root]:
-            for name, value in node._data.items():
+            for name, value in iteritems(node._data):
                 if name not in rv:
                     rv[name] = value
         return rv
 
     def iteritems(self):
-        for item in self._flatten().items():
+        for item in iteritems(self._flatten()):
             yield item
 
     def iterkeys(self):
-        for item in self._flatten().keys():
+        for item in iterkeys(self._flatten()):
             yield item
 
     def itervalues(self):
-        for item in self._flatten().values():
+        for item in itervalues(self._flatten()):
             yield item
 
     def append(self, child):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
index 30dd144..3b11e83 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/backends/conditional.py
@@ -1,5 +1,5 @@
 import operator
-from six import ensure_text
+from six import ensure_text, iteritems, iterkeys, text_type
 
 from ..node import NodeVisitor, DataNode, ConditionalNode, KeyValueNode, ListNode, ValueNode, BinaryExpressionNode, VariableNode
 from ..parser import parse
@@ -300,9 +300,9 @@
         if isinstance(value, list):
             value_node = ListNode()
             for item in value:
-                value_node.append(ValueNode(str(item)))
+                value_node.append(ValueNode(text_type(item)))
         else:
-            value_node = ValueNode(str(value))
+            value_node = ValueNode(text_type(value))
         if condition is not None:
             if not isinstance(condition, ConditionalNode):
                 conditional_node = ConditionalNode()
@@ -368,17 +368,17 @@
     def _flatten(self):
         rv = {}
         for node in [self, self.root]:
-            for name, value in node._data.items():
+            for name, value in iteritems(node._data):
                 if name not in rv:
                     rv[name] = value
         return rv
 
     def iteritems(self):
-        for item in self._flatten().items():
+        for item in iteritems(self._flatten()):
             yield item
 
     def iterkeys(self):
-        for item in self._flatten().keys():
+        for item in iterkeys(self._flatten()):
             yield item
 
     def iter_properties(self):
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
index 5e9d2b6..0f82d70 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/node.py
@@ -1,3 +1,5 @@
+from six.moves import range
+
 class NodeVisitor(object):
     def visit(self, node):
         # This is ugly as hell, but we don't have multimethods and
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
index f6ae1e2..911efac80 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptmanifest/parser.py
@@ -14,7 +14,8 @@
 
 from __future__ import unicode_literals
 
-from io import BytesIO
+from six import binary_type, text_type, BytesIO, unichr
+from six.moves import range
 
 from .node import (Node, AtomNode, BinaryExpressionNode, BinaryOperatorNode,
                    ConditionalNode, DataNode, IndexNode, KeyValueNode, ListNode,
@@ -49,7 +50,7 @@
          "Reset": object()}
 
 def decode(s):
-    assert isinstance(s, str)
+    assert isinstance(s, text_type)
     return s
 
 
@@ -78,7 +79,7 @@
 
     def tokenize(self, stream):
         self.reset()
-        assert not isinstance(stream, str)
+        assert not isinstance(stream, text_type)
         if isinstance(stream, bytes):
             stream = BytesIO(stream)
         if not hasattr(stream, "name"):
@@ -88,7 +89,7 @@
 
         self.next_line_state = self.line_start_state
         for i, line in enumerate(stream):
-            assert isinstance(line, bytes)
+            assert isinstance(line, binary_type)
             self.state = self.next_line_state
             assert self.state is not None
             states = []
@@ -96,7 +97,7 @@
             self.line_number = i + 1
             self.index = 0
             self.line = line.decode('utf-8').rstrip()
-            assert isinstance(self.line, str)
+            assert isinstance(self.line, text_type)
             while self.state != self.eol_state:
                 states.append(self.state)
                 tokens = self.state()
@@ -504,7 +505,7 @@
             value += self.escape_value(c)
             self.consume()
 
-        return chr(value)
+        return unichr(value)
 
     def escape_value(self, c):
         if '0' <= c <= '9':
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py
index bb1e570e..7182510 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wptrunner.py
@@ -4,6 +4,8 @@
 import os
 import sys
 
+from six import iteritems, itervalues
+
 import wptserve
 from wptserve import sslutils
 
@@ -65,8 +67,6 @@
     manifest_filters = []
 
     include = kwargs["include"]
-    if kwargs["include_file"]:
-        include.extend(testloader.read_include_from_file(kwargs["include_file"]))
     if test_groups:
         include = testloader.update_include_for_groups(test_groups, include)
 
@@ -117,7 +117,7 @@
     run_info, test_loader = get_loader(test_paths, product,
                                        run_info_extras=run_info_extras, **kwargs)
 
-    for test_type, tests in test_loader.disabled_tests.items():
+    for test_type, tests in iteritems(test_loader.disabled_tests):
         for test in tests:
             rv.append({"test": test.id, "reason": test.disabled()})
     print(json.dumps(rv, indent=2))
@@ -144,7 +144,7 @@
         if kwargs["debug_test"]:
             return True
         tests = test_loader.tests
-        is_single_testharness = (sum(len(item) for item in tests.values()) == 1 and
+        is_single_testharness = (sum(len(item) for item in itervalues(tests)) == 1 and
                                  len(tests.get("testharness", [])) == 1)
         if kwargs["repeat"] == 1 and kwargs["rerun"] == 1 and is_single_testharness:
             return True
@@ -201,7 +201,6 @@
         skipped_tests = 0
         test_total = 0
         unexpected_total = 0
-        unexpected_pass_total = 0
 
         if len(test_loader.test_ids) == 0 and kwargs["test_list"]:
             logger.critical("Unable to find any tests at the path(s):")
@@ -256,7 +255,6 @@
 
                 test_count = 0
                 unexpected_count = 0
-                unexpected_pass_count = 0
 
                 tests = []
                 for test_type in test_loader.test_types:
@@ -347,13 +345,10 @@
                             raise
                         test_count += manager_group.test_count()
                         unexpected_count += manager_group.unexpected_count()
-                        unexpected_pass_count += manager_group.unexpected_pass_count()
                 recording.set(["after-end"])
                 test_total += test_count
                 unexpected_total += unexpected_count
-                unexpected_pass_total += unexpected_pass_count
-                logger.info("Got %i unexpected results, with %i unexpected passes" %
-                            (unexpected_count, unexpected_pass_count))
+                logger.info("Got %i unexpected results" % unexpected_count)
                 logger.suite_end()
                 if repeat_until_unexpected and unexpected_total > 0:
                     break
@@ -375,13 +370,6 @@
         logger.info("Tolerating %s unexpected results" % unexpected_total)
         return True
 
-    all_unexpected_passed = (unexpected_total and
-                             unexpected_total == unexpected_pass_total)
-    if all_unexpected_passed and not kwargs["fail_on_unexpected_pass"]:
-        logger.info("Tolerating %i unexpected results because they all PASS" %
-                    unexpected_pass_total)
-        return True
-
     return unexpected_total == 0
 
 
diff --git a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py
index b7a7cec1..ed9184e 100644
--- a/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py
+++ b/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/wpttest.py
@@ -1,8 +1,9 @@
 import os
 import subprocess
 import sys
+from six.moves.urllib.parse import urljoin
 from collections import defaultdict
-from urllib.parse import urljoin
+from six import iteritems, string_types
 
 from .wptmanifest.parser import atoms
 
@@ -306,7 +307,7 @@
         rv = {}
         for meta in self.itermeta(None):
             threshold = meta.leak_threshold
-            for key, value in threshold.items():
+            for key, value in iteritems(threshold):
                 if key not in rv:
                     rv[key] = value
         return rv
@@ -348,7 +349,7 @@
 
         try:
             expected = metadata.get("expected")
-            if isinstance(expected, str):
+            if isinstance(expected, string_types):
                 return expected
             elif isinstance(expected, list):
                 return expected[0]
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py
index 843f6e6..4d653f5 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/config.py
@@ -2,7 +2,9 @@
 import logging
 import os
 from collections import defaultdict
-from collections.abc import Mapping
+
+from six.moves.collections_abc import Mapping
+from six import integer_types, iteritems, itervalues, string_types
 
 from . import sslutils
 from .utils import get_port
@@ -18,7 +20,7 @@
 
 def _merge_dict(base_dict, override_dict):
     rv = base_dict.copy()
-    for key, value in base_dict.items():
+    for key, value in iteritems(base_dict):
         if key in override_dict:
             if isinstance(value, dict):
                 rv[key] = _merge_dict(value, override_dict[key])
@@ -87,7 +89,7 @@
                 target = target[part]
             value = target[key[-1]]
             if isinstance(value, dict):
-                target[key[-1]] = {k:v for (k,v) in value.items() if not k.startswith("op")}
+                target[key[-1]] = {k:v for (k,v) in iteritems(value) if not k.startswith("op")}
             else:
                 target[key[-1]] = [x for x in value if not x.startswith("op")]
 
@@ -96,9 +98,9 @@
 
 def json_types(obj):
     if isinstance(obj, dict):
-        return {key: json_types(value) for key, value in obj.items()}
-    if (isinstance(obj, str) or
-        isinstance(obj, int) or
+        return {key: json_types(value) for key, value in iteritems(obj)}
+    if (isinstance(obj, string_types) or
+        isinstance(obj, integer_types) or
         isinstance(obj, float) or
         isinstance(obj, bool) or
         obj is None):
@@ -201,13 +203,13 @@
                 self.log_level = level_name
             self._logger_name = logger.name
 
-        for k, v in self._default.items():
+        for k, v in iteritems(self._default):
             self._data[k] = kwargs.pop(k, v)
 
         self._data["subdomains"] = subdomains
         self._data["not_subdomains"] = not_subdomains
 
-        for k, new_k in _renamed_props.items():
+        for k, new_k in iteritems(_renamed_props):
             if k in kwargs:
                 self.logger.warning(
                     "%s in config is deprecated; use %s instead" % (
@@ -240,7 +242,7 @@
             if k in override:
                 self._set_override(k, override.pop(k))
 
-        for k, new_k in _renamed_props.items():
+        for k, new_k in iteritems(_renamed_props):
             if k in override:
                 self.logger.warning(
                     "%s in config is deprecated; use %s instead" % (
@@ -285,7 +287,7 @@
 
     def _get_ports(self, data):
         new_ports = defaultdict(list)
-        for scheme, ports in data["ports"].items():
+        for scheme, ports in iteritems(data["ports"]):
             if scheme in ["wss", "https"] and not sslutils.get_cls(data["ssl"]["type"]).ssl_enabled:
                 continue
             for i, port in enumerate(ports):
@@ -299,7 +301,7 @@
         hosts[""] = data["browser_host"]
 
         rv = {}
-        for name, host in hosts.items():
+        for name, host in iteritems(hosts):
             rv[name] = {subdomain: (subdomain.encode("idna").decode("ascii") + u"." + host)
                         for subdomain in data["subdomains"]}
             rv[name][""] = host
@@ -311,7 +313,7 @@
         hosts[""] = data["browser_host"]
 
         rv = {}
-        for name, host in hosts.items():
+        for name, host in iteritems(hosts):
             rv[name] = {subdomain: (subdomain.encode("idna").decode("ascii") + u"." + host)
                         for subdomain in data["not_subdomains"]}
         return rv
@@ -325,13 +327,13 @@
 
     def _get_domains_set(self, data):
         return {domain
-                for per_host_domains in data["domains"].values()
-                for domain in per_host_domains.values()}
+                for per_host_domains in itervalues(data["domains"])
+                for domain in itervalues(per_host_domains)}
 
     def _get_not_domains_set(self, data):
         return {domain
-                for per_host_domains in data["not_domains"].values()
-                for domain in per_host_domains.values()}
+                for per_host_domains in itervalues(data["not_domains"])
+                for domain in itervalues(per_host_domains)}
 
     def _get_all_domains_set(self, data):
         return data["domains_set"] | data["not_domains_set"]
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/handlers.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/handlers.py
index 9eb4a44c..0fc11c19 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/handlers.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/handlers.py
@@ -3,7 +3,8 @@
 import traceback
 from collections import defaultdict
 
-from urllib.parse import quote, unquote, urljoin
+from six.moves.urllib.parse import quote, unquote, urljoin
+from six import iteritems
 
 from .constants import content_types
 from .pipes import Pipeline, template
@@ -481,7 +482,7 @@
         self.data = data
 
         self.resp_headers = [("Content-Type", content_type)]
-        for k, v in headers.items():
+        for k, v in iteritems(headers):
             self.resp_headers.append((k.replace("_", "-"), v))
 
         self.handler = handler(self.handle_request)
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/pipes.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/pipes.py
index 6845c33..bbf25e6f 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/pipes.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/pipes.py
@@ -7,7 +7,8 @@
 import time
 import uuid
 
-from io import BytesIO
+from six.moves import StringIO
+from six import text_type, binary_type
 
 try:
     from html import escape
@@ -304,7 +305,7 @@
         return ("var", token)
 
     def tokenize(self, string):
-        assert isinstance(string, bytes)
+        assert isinstance(string, binary_type)
         return self.scanner.scan(string)[0]
 
     scanner = re.Scanner([(br"\$\w+:", var),
@@ -319,7 +320,7 @@
 
     def __getitem__(self, key):
         try:
-            if isinstance(key, str):
+            if isinstance(key, text_type):
                 key = key.encode('iso-8859-1')
             return self.params.first(key)
         except KeyError:
@@ -407,7 +408,7 @@
 
     @staticmethod
     def file_hash(request, algorithm, path):
-        assert isinstance(algorithm, str)
+        assert isinstance(algorithm, text_type)
         if algorithm not in SubFunctions.supported_algorithms:
             raise ValueError("Unsupported encryption algorithm: '%s'" % algorithm)
 
@@ -459,12 +460,12 @@
         tokens = deque(tokens)
 
         token_type, field = tokens.popleft()
-        assert isinstance(field, str)
+        assert isinstance(field, text_type)
 
         if token_type == "var":
             variable = field
             token_type, field = tokens.popleft()
-            assert isinstance(field, str)
+            assert isinstance(field, text_type)
         else:
             variable = None
 
@@ -515,7 +516,7 @@
                     "unexpected token type %s (token '%r'), expected ident or arguments" % (ttype, field)
                 )
 
-        assert isinstance(value, (int, (bytes, str))), tokens
+        assert isinstance(value, (int, (binary_type, text_type))), tokens
 
         if variable is not None:
             variables[variable] = value
@@ -526,10 +527,10 @@
         # Should possibly support escaping for other contexts e.g. script
         # TODO: read the encoding of the response
         # cgi.escape() only takes text strings in Python 3.
-        if isinstance(value, bytes):
+        if isinstance(value, binary_type):
             value = value.decode("utf-8")
         elif isinstance(value, int):
-            value = str(value)
+            value = text_type(value)
         return escape_func(value).encode("utf-8")
 
     template_regexp = re.compile(br"{{([^}]*)}}")
@@ -548,7 +549,7 @@
     content = resolve_content(response)
     response.headers.set("Content-Encoding", "gzip")
 
-    out = BytesIO()
+    out = StringIO()
     with gzip_module.GzipFile(fileobj=out, mode="w") as f:
         f.write(content)
     response.content = out.getvalue()
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/request.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/request.py
index 76644cc49..dbfe067 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/request.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/request.py
@@ -2,9 +2,9 @@
 import cgi
 import tempfile
 
-from http.cookies import BaseCookie
-from io import BytesIO
-from urllib.parse import parse_qsl, urlsplit
+from six import BytesIO, binary_type, iteritems, PY3
+from six.moves.http_cookies import BaseCookie
+from six.moves.urllib.parse import parse_qsl, urlsplit
 
 from . import stash
 from .utils import HTTPException, isomorphic_encode, isomorphic_decode
@@ -301,8 +301,9 @@
         if self._GET is None:
             kwargs = {
                 "keep_blank_values": True,
-                "encoding": "iso-8859-1",
             }
+            if PY3:
+                kwargs["encoding"] = "iso-8859-1"
             params = parse_qsl(self.url_parts.query, **kwargs)
             self._GET = MultiDict()
             for key, value in params:
@@ -320,8 +321,9 @@
                 "environ": {"REQUEST_METHOD": self.method},
                 "headers": self.raw_headers,
                 "keep_blank_values": True,
-                "encoding": "iso-8859-1",
             }
+            if PY3:
+                kwargs["encoding"] = "iso-8859-1"
             fs = cgi.FieldStorage(**kwargs)
             self._POST = MultiDict.from_field_storage(fs)
             self.raw_input.seek(pos)
@@ -334,7 +336,7 @@
             cookie_headers = self.headers.get("cookie", b"")
             parser.load(cookie_headers)
             cookies = Cookies()
-            for key, value in parser.items():
+            for key, value in iteritems(parser):
                 cookies[isomorphic_encode(key)] = CookieValue(value)
             self._cookies = cookies
         return self._cookies
@@ -628,9 +630,11 @@
         This overrides and calls BaseCookie.load. Unlike BaseCookie.load, it
         does not accept dictionaries.
         """
-        assert isinstance(rawdata, bytes)
-        # BaseCookie.load expects a native string
-        super(BinaryCookieParser, self).load(isomorphic_decode(rawdata))
+        assert isinstance(rawdata, binary_type)
+        if PY3:
+            # BaseCookie.load expects a native string, which in Python 3 is text.
+            rawdata = isomorphic_decode(rawdata)
+        super(BinaryCookieParser, self).load(rawdata)
 
 
 class Cookies(MultiDict):
@@ -671,7 +675,7 @@
 
         if "authorization" in headers:
             header = headers.get("authorization")
-            assert isinstance(header, bytes)
+            assert isinstance(header, binary_type)
             auth_type, data = header.split(b" ", 1)
             if auth_type in auth_schemes:
                 self.username, self.password = auth_schemes[auth_type](data)
@@ -679,6 +683,6 @@
                 raise HTTPException(400, "Unsupported authentication scheme %s" % auth_type)
 
     def decode_basic(self, data):
-        assert isinstance(data, bytes)
+        assert isinstance(data, binary_type)
         decoded_data = base64.b64decode(data)
         return decoded_data.split(b":", 1)
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py
index 8763cca..6e5ee11 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/response.py
@@ -6,8 +6,9 @@
 import uuid
 
 from hpack.struct import HeaderTuple
-from http.cookies import BaseCookie, Morsel
 from hyperframe.frame import HeadersFrame, DataFrame, ContinuationFrame
+from six import binary_type, text_type, integer_types, itervalues, PY3
+from six.moves.http_cookies import BaseCookie, Morsel
 
 from .constants import response_codes, h2_headers
 from .logger import get_logger
@@ -90,7 +91,7 @@
                 message = value[1]
                 # Only call str() if message is not a string type, so that we
                 # don't get `str(b"foo") == "b'foo'"` in Python 3.
-                if not isinstance(message, (bytes, str)):
+                if not isinstance(message, (binary_type, text_type)):
                     message = str(message)
                 self._status = (code, message)
         else:
@@ -121,8 +122,9 @@
             max_age = 0
             expires = timedelta(days=-1)
 
-        name = isomorphic_decode(name)
-        value = isomorphic_decode(value)
+        if PY3:
+            name = isomorphic_decode(name)
+            value = isomorphic_decode(value)
 
         days = {i+1: name for i, name in enumerate(["jan", "feb", "mar",
                                                     "apr", "may", "jun",
@@ -161,11 +163,15 @@
 
     def unset_cookie(self, name):
         """Remove a cookie from those that are being sent with the response"""
-        name = isomorphic_decode(name)
+        if PY3:
+            name = isomorphic_decode(name)
         cookies = self.headers.get("Set-Cookie")
         parser = BaseCookie()
         for cookie in cookies:
-            parser.load(isomorphic_decode(cookie))
+            if PY3:
+                # BaseCookie.load expects a text string.
+                cookie = isomorphic_decode(cookie)
+            parser.load(cookie)
 
         if name in parser.keys():
             del self.headers["Set-Cookie"]
@@ -193,9 +199,9 @@
                           string facilitating non-streaming operations like
                           template substitution.
         """
-        if isinstance(self.content, bytes):
+        if isinstance(self.content, binary_type):
             yield self.content
-        elif isinstance(self.content, str):
+        elif isinstance(self.content, text_type):
             yield self.content.encode(self.encoding)
         elif hasattr(self.content, "read"):
             if read_file:
@@ -250,7 +256,7 @@
     def __init__(self, boundary=None, default_content_type=None):
         self.items = []
         if boundary is None:
-            boundary = str(uuid.uuid4())
+            boundary = text_type(uuid.uuid4())
         self.boundary = boundary
         self.default_content_type = default_content_type
 
@@ -278,7 +284,7 @@
 
 class MultipartPart(object):
     def __init__(self, data, content_type=None, headers=None):
-        assert isinstance(data, bytes), data
+        assert isinstance(data, binary_type), data
         self.headers = ResponseHeaders()
 
         if content_type is not None:
@@ -297,8 +303,8 @@
     def to_bytes(self):
         rv = []
         for key, value in self.headers:
-            assert isinstance(key, bytes)
-            assert isinstance(value, bytes)
+            assert isinstance(key, binary_type)
+            assert isinstance(value, binary_type)
             rv.append(b"%s: %s" % (key, value))
         rv.append(b"")
         rv.append(self.data)
@@ -307,7 +313,7 @@
 
 def _maybe_encode(s):
     """Encode a string or an int into binary data using isomorphic_encode()."""
-    if isinstance(s, int):
+    if isinstance(s, integer_types):
         return b"%i" % (s,)
     return isomorphic_encode(s)
 
@@ -371,7 +377,7 @@
         self.set(key, value)
 
     def __iter__(self):
-        for key, values in self.data.values():
+        for key, values in itervalues(self.data):
             for value in values:
                 yield key, value
 
@@ -441,10 +447,10 @@
         for header, value in headers:
             # h2_headers are native strings
             # header field names are strings of ASCII
-            if isinstance(header, bytes):
+            if isinstance(header, binary_type):
                 header = header.decode('ascii')
             # value in headers can be either string or integer
-            if isinstance(value, bytes):
+            if isinstance(value, binary_type):
                 value = self.decode(value)
             if header in h2_headers:
                 header = ':' + header
@@ -476,7 +482,7 @@
         :param last: Flag to signal if this is the last frame in stream.
         :param stream_id: Id of stream to send frame on. Will use the request stream ID if None
         """
-        if isinstance(item, (str, bytes)):
+        if isinstance(item, (text_type, binary_type)):
             data = BytesIO(self.encode(item))
         else:
             data = item
@@ -632,18 +638,18 @@
 
     def decode(self, data):
         """Convert bytes to unicode according to response.encoding."""
-        if isinstance(data, bytes):
+        if isinstance(data, binary_type):
             return data.decode(self._response.encoding)
-        elif isinstance(data, str):
+        elif isinstance(data, text_type):
             return data
         else:
             raise ValueError(type(data))
 
     def encode(self, data):
         """Convert unicode to bytes according to response.encoding."""
-        if isinstance(data, bytes):
+        if isinstance(data, binary_type):
             return data
-        elif isinstance(data, str):
+        elif isinstance(data, text_type):
             return data.encode(self._response.encoding)
         else:
             raise ValueError
@@ -701,7 +707,7 @@
         if not self.write(b": "):
             return False
         if isinstance(value, int):
-            if not self.write(str(value)):
+            if not self.write(text_type(value)):
                 return False
         elif not self.write(value):
             return False
@@ -714,7 +720,7 @@
                 if not self.write_header(name, f()):
                     return False
 
-        if (isinstance(self._response.content, (bytes, str)) and
+        if (isinstance(self._response.content, (binary_type, text_type)) and
             not self._seen_header("content-length")):
             #Would be nice to avoid double-encoding here
             if not self.write_header("Content-Length", len(self.encode(self._response.content))):
@@ -761,7 +767,7 @@
         """Writes the data 'as is'"""
         if data is None:
             raise ValueError('data cannot be None')
-        if isinstance(data, (str, bytes)):
+        if isinstance(data, (text_type, binary_type)):
             # Deliberately allows both text and binary types. See `self.encode`.
             return self.write(data)
         else:
@@ -799,9 +805,9 @@
 
     def encode(self, data):
         """Convert unicode to bytes according to response.encoding."""
-        if isinstance(data, bytes):
+        if isinstance(data, binary_type):
             return data
-        elif isinstance(data, str):
+        elif isinstance(data, text_type):
             return data.encode(self._response.encoding)
         else:
             raise ValueError("data %r should be text or binary, but is %s" % (data, type(data)))
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/router.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/router.py
index 5a91de30..d1704a7 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/router.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/router.py
@@ -3,6 +3,7 @@
 import sys
 
 from .logger import get_logger
+from six import binary_type, text_type
 
 any_method = object()
 
@@ -145,7 +146,7 @@
                         object and the response object.
 
         """
-        if isinstance(methods, (bytes, str)) or methods is any_method:
+        if isinstance(methods, (binary_type, text_type)) or methods is any_method:
             methods = [methods]
         for method in methods:
             self.routes.append((method, compile_path_match(path), handler))
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py
index cfa86f99..2b5ed4a2 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/server.py
@@ -1,16 +1,18 @@
+from six.moves import BaseHTTPServer
 import errno
-import http.server
 import os
 import socket
-from socketserver import ThreadingMixIn
+from six.moves.socketserver import ThreadingMixIn
 import ssl
 import sys
 import threading
 import time
 import traceback
+from six import binary_type, text_type
 import uuid
 from collections import OrderedDict
-from queue import Queue
+
+from six.moves.queue import Queue
 
 from h2.config import H2Configuration
 from h2.connection import H2Connection
@@ -19,7 +21,7 @@
 from h2.settings import SettingCodes
 from h2.utilities import extract_method_header
 
-from urllib.parse import urlsplit, urlunsplit
+from six.moves.urllib.parse import urlsplit, urlunsplit
 
 from mod_pywebsocket import dispatch
 from mod_pywebsocket.handshake import HandshakeException
@@ -36,12 +38,13 @@
 
 # We need to stress test that browsers can send/receive many headers (there is
 # no specified limit), but the Python stdlib has an arbitrary limit of 100
-# headers. Hitting the limit leads to HTTP 431, so we monkey patch it higher.
+# headers. Hitting the limit would produce an exception that is silently caught
+# in Python 2 but leads to HTTP 431 in Python 3, so we monkey patch it higher.
 # https://bugs.python.org/issue26586
 # https://github.com/web-platform-tests/wpt/pull/24451
-import http.client
-assert isinstance(getattr(http.client, '_MAXHEADERS'), int)
-setattr(http.client, '_MAXHEADERS', 512)
+from six.moves import http_client
+assert isinstance(getattr(http_client, '_MAXHEADERS'), int)
+setattr(http_client, '_MAXHEADERS', 512)
 
 """
 HTTP server designed for testing purposes.
@@ -103,7 +106,7 @@
         :param output_path: Path to replace the input path with in
                             the request.
         """
-        if isinstance(methods, (bytes, str)):
+        if isinstance(methods, (binary_type, text_type)):
             methods = [methods]
         self.rules[input_path] = (methods, output_path)
 
@@ -126,7 +129,7 @@
                 request_handler.path = new_url
 
 
-class WebTestServer(ThreadingMixIn, http.server.HTTPServer):
+class WebTestServer(ThreadingMixIn, BaseHTTPServer.HTTPServer):
     allow_reuse_address = True
     acceptable_errors = (errno.EPIPE, errno.ECONNABORTED)
     request_queue_size = 2000
@@ -187,7 +190,8 @@
         else:
             hostname_port = ("",server_address[1])
 
-        http.server.HTTPServer.__init__(self, hostname_port, request_handler_cls, **kwargs)
+        #super doesn't work here because BaseHTTPServer.HTTPServer is old-style
+        BaseHTTPServer.HTTPServer.__init__(self, hostname_port, request_handler_cls, **kwargs)
 
         if config is not None:
             Server.config = config
@@ -232,12 +236,12 @@
             self.logger.error(traceback.format_exc())
 
 
-class BaseWebTestRequestHandler(http.server.BaseHTTPRequestHandler):
+class BaseWebTestRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
     """RequestHandler for WebTestHttpd"""
 
     def __init__(self, *args, **kwargs):
         self.logger = get_logger()
-        http.server.BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
+        BaseHTTPServer.BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
 
     def finish_handling_h1(self, request_line_is_valid):
 
@@ -478,19 +482,14 @@
         try:
             handshaker.do_handshake()
         except HandshakeException as e:
-            self.logger.info('Handshake failed for error: %s' % e)
+            self.logger.info('Handshake failed for error: %s', e)
             h2response.set_error(e.status)
             h2response.write()
             return
 
         # h2 Handshaker prepares the headers but does not send them down the
         # wire. Flush the headers here.
-        try:
-            h2response.write_status_headers()
-        except StreamClosedError:
-            # work around https://github.com/web-platform-tests/wpt/issues/27786
-            # The stream was already closed.
-            return
+        h2response.write_status_headers()
 
         request_wrapper._dispatcher = dispatcher
 
@@ -523,13 +522,7 @@
 
     def _stream_ws_sub_thread(self, request, stream_handler, queue):
         dispatcher = request._dispatcher
-        try:
-            dispatcher.transfer_data(request)
-        except StreamClosedError:
-            # work around https://github.com/web-platform-tests/wpt/issues/27786
-            # The stream was already closed.
-            queue.put(None)
-            return
+        dispatcher.transfer_data(request)
 
         stream_id = stream_handler.h2_stream_id
         with stream_handler.conn as connection:
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/sslutils/openssl.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/sslutils/openssl.py
index 87a8cc9..64f6d5f 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/sslutils/openssl.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/sslutils/openssl.py
@@ -6,6 +6,8 @@
 import tempfile
 from datetime import datetime, timedelta
 
+from six import iteritems, PY2
+
 # Amount of time beyond the present to consider certificates "expired." This
 # allows certificates to be proactively re-generated in the "buffer" period
 # prior to their exact expiration time.
@@ -16,7 +18,11 @@
     """makes sure s is an instance of str, converting with encoding if needed"""
     if isinstance(s, str):
         return s
-    return s.decode(encoding)
+
+    if PY2:
+        return s.encode(encoding)
+    else:
+        return s.decode(encoding)
 
 
 class OpenSSL(object):
@@ -73,7 +79,7 @@
         # Copy the environment, converting to plain strings. Win32 StartProcess
         # is picky about all the keys/values being str (on both Py2/3).
         env = {}
-        for k, v in os.environ.items():
+        for k, v in iteritems(os.environ):
             env[_ensure_str(k, "utf8")] = _ensure_str(v, "utf8")
 
         if self.base_conf_path is not None:
@@ -318,7 +324,7 @@
             end_date_str = openssl("x509",
                                    "-noout",
                                    "-enddate",
-                                   "-in", cert_path).decode("utf8").split("=", 1)[1].strip()
+                                   "-in", cert_path).split("=", 1)[1].strip()
             # Not sure if this works in other locales
             end_date = datetime.strptime(end_date_str, "%b %d %H:%M:%S %Y %Z")
             time_buffer = timedelta(**CERT_EXPIRY_BUFFER)
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/stash.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/stash.py
index 66c2713..bf6e5992 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/stash.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/stash.py
@@ -1,10 +1,12 @@
 import base64
 import json
 import os
+import six
 import threading
 import uuid
 
 from multiprocessing.managers import AcquirerProxy, BaseManager, DictProxy
+from six import text_type, binary_type
 
 from .utils import isomorphic_encode
 
@@ -65,10 +67,10 @@
 
 
 def start_server(address=None, authkey=None, mp_context=None):
-    if isinstance(authkey, str):
+    if isinstance(authkey, text_type):
         authkey = authkey.encode("ascii")
     kwargs = {}
-    if mp_context is not None:
+    if six.PY3 and mp_context is not None:
         kwargs["ctx"] = mp_context
     manager = ServerDictManager(address, authkey, **kwargs)
     manager.start()
@@ -158,7 +160,7 @@
         # This key format is required to support using the path. Since the data
         # passed into the stash can be a DictProxy which wouldn't detect
         # changes when writing to a subdict.
-        if isinstance(key, bytes):
+        if isinstance(key, binary_type):
             # UUIDs are within the ASCII charset.
             key = key.decode('ascii')
         return (isomorphic_encode(path), uuid.UUID(key).bytes)
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/utils.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/utils.py
index ed74b73..df0b3f3 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/utils.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/utils.py
@@ -1,5 +1,6 @@
 import socket
 
+from six import binary_type, text_type
 
 from .logger import get_logger
 
@@ -7,18 +8,18 @@
 def isomorphic_decode(s):
     """Decodes a binary string into a text string using iso-8859-1.
 
-    Returns `str`. The function is a no-op if the argument already has a text
-    type. iso-8859-1 is chosen because it is an 8-bit encoding whose code
-    points range from 0x0 to 0xFF and the values are the same as the binary
-    representations, so any binary string can be decoded into and encoded from
-    iso-8859-1 without any errors or data loss. Python 3 also uses iso-8859-1
-    (or latin-1) extensively in http:
+    Returns `unicode` in Python 2 and `str` in Python 3. The function is a
+    no-op if the argument already has a text type. iso-8859-1 is chosen because
+    it is an 8-bit encoding whose code points range from 0x0 to 0xFF and the
+    values are the same as the binary representations, so any binary string can
+    be decoded into and encoded from iso-8859-1 without any errors or data
+    loss. Python 3 also uses iso-8859-1 (or latin-1) extensively in http:
     https://github.com/python/cpython/blob/273fc220b25933e443c82af6888eb1871d032fb8/Lib/http/client.py#L213
     """
-    if isinstance(s, str):
+    if isinstance(s, text_type):
         return s
 
-    if isinstance(s, bytes):
+    if isinstance(s, binary_type):
         return s.decode("iso-8859-1")
 
     raise TypeError("Unexpected value (expecting string-like): %r" % s)
@@ -27,13 +28,14 @@
 def isomorphic_encode(s):
     """Encodes a text-type string into binary data using iso-8859-1.
 
-    Returns `bytes`. The function is a no-op if the argument already has a
-    binary type. This is the counterpart of isomorphic_decode.
+    Returns `str` in Python 2 and `bytes` in Python 3. The function is a no-op
+    if the argument already has a binary type. This is the counterpart of
+    isomorphic_decode.
     """
-    if isinstance(s, bytes):
+    if isinstance(s, binary_type):
         return s
 
-    if isinstance(s, str):
+    if isinstance(s, text_type):
         return s.encode("iso-8859-1")
 
     raise TypeError("Unexpected value (expecting string-like): %r" % s)
@@ -86,7 +88,6 @@
         42,    # name
         43,    # nicname
         53,    # domain
-        69,    # tftp
         77,    # priv-rjs
         79,    # finger
         87,    # ttylink
@@ -104,10 +105,8 @@
         119,   # nntp
         123,   # ntp
         135,   # loc-srv / epmap
-        137,   # netbios-ns
-        139,   # netbios-ssn
+        139,   # netbios
         143,   # imap2
-        161,   # snmp
         179,   # bgp
         389,   # ldap
         427,   # afp (alternate)
@@ -130,7 +129,6 @@
         636,   # ldap+ssl
         993,   # ldap+ssl
         995,   # pop3+ssl
-        1719,  # h323gatestat
         1720,  # h323hostcall
         1723,  # pptp
         2049,  # nfs
@@ -139,7 +137,6 @@
         5060,  # sip
         5061,  # sips
         6000,  # x11
-        6566,  # sane-port
         6665,  # irc (alternate)
         6666,  # irc (alternate)
         6667,  # irc (default)
diff --git a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
index c813ecb..98796c0 100644
--- a/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
+++ b/third_party/wpt_tools/wpt/tools/wptserve/wptserve/ws_h2_handshake.py
@@ -11,6 +11,8 @@
 from mod_pywebsocket.stream import Stream
 from mod_pywebsocket.stream import StreamOptions
 from mod_pywebsocket import util
+from six.moves import map
+from six.moves import range
 
 # TODO: We are using "private" methods of pywebsocket. We might want to
 # refactor pywebsocket to expose those methods publicly. Also, _get_origin
diff --git a/third_party/wpt_tools/wpt/wpt b/third_party/wpt_tools/wpt/wpt
index eac84b6..36d0bed4 100755
--- a/third_party/wpt_tools/wpt/wpt
+++ b/third_party/wpt_tools/wpt/wpt
@@ -1,11 +1,34 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 
 if __name__ == "__main__":
     import sys
-    if (sys.version_info.major < 3 or
-            (sys.version_info.major == 3 and sys.version_info.minor < 6)):
-        sys.stderr.write("wpt requires Python 3.6 or higher\n")
-        sys.exit(1)
-
     from tools.wpt import wpt
-    wpt.main()
+    args, extra = wpt.parse_args(sys.argv[1:])
+    commands = wpt.load_commands()
+    py3only = commands[args.command]["py3only"]
+
+    if (args.py2) and sys.version_info.major > 2:
+        if py3only:
+            sys.stderr.write("This command only works with Python 3\n")
+            sys.exit(1)
+        from subprocess import call
+        try:
+            sys.exit(call(['python2'] + sys.argv))
+        except OSError as e:
+            if e.errno == 2:
+                sys.stderr.write("python2 is needed to run this command\n")
+                sys.exit(1)
+            else:
+                raise
+    elif (not args.py2) and sys.version_info.major < 3:
+        from subprocess import call
+        try:
+            sys.exit(call(['python3'] + sys.argv))
+        except OSError as e:
+            if e.errno == 2:
+                sys.stderr.write("python3 is needed to run this command\n")
+                sys.exit(1)
+            else:
+                raise
+    else:
+        wpt.main()
diff --git a/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh b/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh
index 44db803..b601688 100755
--- a/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh
+++ b/tools/clang/rewrite_raw_ptr_fields/rewrite-multiple-platforms.sh
@@ -120,7 +120,7 @@
     time tools/clang/scripts/run_tool.py \
         $TARGET_OS_OPTION \
         --tool rewrite_raw_ptr_fields \
-        --tool-arg=--exclude-fields=~/scratch/combined-fields-to-ignore.txt \
+        --tool-arg=--exclude-fields="$HOME/scratch/combined-fields-to-ignore.txt" \
         --tool-arg=--exclude-paths=$REWRITER_SRC_DIR/manual-paths-to-ignore.txt \
         -p $OUT_DIR \
         $COMPILE_DIRS > ~/scratch/rewriter-$PLATFORM.main.out
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index a987ebe0..9edc193 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -422,6 +422,10 @@
     "META": {"sizes": {"includes": [50],}},
     "includes": [2680],
   },
+  "<(SHARED_INTERMEDIATE_DIR)/chromeos/components/personalization_app/resources/chromeos_personalization_app_resources.grd": {
+    "META": {"sizes": {"includes": [50],}},
+    "includes": [2690],
+  },
   # END chromeos/ section.
 
   # START components/ section.
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 72c34ba..473f596 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -584,11 +584,8 @@
     'chromium.swangle': {
       'linux-swangle-chromium-x64': 'gpu_tests_release_trybot',
       'linux-swangle-tot-angle-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-tot-angle-x86': 'angle_deqp_release_trybot_x86',
       'linux-swangle-tot-swiftshader-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-tot-swiftshader-x86': 'angle_deqp_release_trybot_x86',
       'linux-swangle-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-x86': 'angle_deqp_release_trybot_x86',
       'mac-swangle-chromium-x64': 'gpu_tests_release_trybot_deterministic_mac',
       'win-swangle-chromium-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win-swangle-tot-angle-x64': 'angle_deqp_release_trybot',
@@ -796,6 +793,7 @@
       'android-pie-arm64-rel': 'android_release_trybot_arm64_webview_google_expectations',
       'android-pie-arm64-wpt-rel-non-cq': 'android_release_trybot_arm64_webview_google',
       'android-pie-x86-rel': 'android_release_trybot_x86_fastbuild_webview_google',
+      'android-weblayer-pie-x86-rel-tests': 'android_release_trybot_minimal_symbols_x86_fastbuild_webview_google',
       'android-weblayer-pie-x86-fyi-rel': 'android_release_trybot_x86_fastbuild_webview_google',
       'android-weblayer-pie-x86-wpt-fyi-rel': 'android_release_trybot_x86_fastbuild_webview_google',
       'android-webview-pie-arm64-fyi-rel': 'android_release_trybot_arm64_webview_google',
@@ -1101,11 +1099,8 @@
     'tryserver.chromium.swangle': {
       'linux-swangle-chromium-try-x64': 'gpu_tests_release_trybot',
       'linux-swangle-try-tot-angle-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-try-tot-angle-x86': 'angle_deqp_release_trybot_x86',
       'linux-swangle-try-tot-swiftshader-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-try-tot-swiftshader-x86': 'angle_deqp_release_trybot_x86',
       'linux-swangle-try-x64': 'angle_deqp_release_trybot',
-      'linux-swangle-try-x86': 'angle_deqp_release_trybot_x86',
       'mac-swangle-chromium-try-x64': 'gpu_tests_release_trybot_deterministic_mac',
       'win-swangle-chromium-try-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win-swangle-try-tot-angle-x64': 'angle_deqp_release_trybot',
@@ -1457,6 +1452,11 @@
       'webview_google',
     ],
 
+    'android_release_trybot_minimal_symbols_x86_fastbuild_webview_google': [
+      'android', 'release_trybot', 'minimal_symbols', 'x86',
+      'strip_debug_info', 'android_fastbuild', 'webview_google',
+    ],
+
     'android_release_trybot_x86_fastbuild_resource_allowlisting_webview_google': [
       'android', 'release_trybot', 'x86', 'android_fastbuild',
       'resource_allowlisting', 'webview_google',
diff --git a/tools/mb/mb_config_expectations/chromium.swangle.json b/tools/mb/mb_config_expectations/chromium.swangle.json
index 8bf7e80..21bc3b62 100644
--- a/tools/mb/mb_config_expectations/chromium.swangle.json
+++ b/tools/mb/mb_config_expectations/chromium.swangle.json
@@ -20,17 +20,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-tot-angle-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "linux-swangle-tot-swiftshader-x64": {
     "gn_args": {
       "build_angle_deqp_tests": true,
@@ -41,17 +30,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-tot-swiftshader-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "linux-swangle-x64": {
     "gn_args": {
       "build_angle_deqp_tests": true,
@@ -62,17 +40,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "mac-swangle-chromium-x64": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.android.json b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
index d5e0c9f..89d4d7d9 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.android.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.android.json
@@ -406,6 +406,23 @@
       "use_goma": true
     }
   },
+  "android-weblayer-pie-x86-rel-tests": {
+    "gn_args": {
+      "dcheck_always_on": true,
+      "disable_android_lint": true,
+      "ffmpeg_branding": "Chrome",
+      "is_component_build": false,
+      "is_debug": false,
+      "proprietary_codecs": true,
+      "strip_debug_info": true,
+      "symbol_level": 1,
+      "system_webview_package_name": "com.google.android.webview",
+      "target_cpu": "x86",
+      "target_os": "android",
+      "use_errorprone_java_compiler": false,
+      "use_goma": true
+    }
+  },
   "android-weblayer-pie-x86-wpt-fyi-rel": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
index 2a3fdf0..3f97205 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.swangle.json
@@ -20,17 +20,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-try-tot-angle-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "linux-swangle-try-tot-swiftshader-x64": {
     "gn_args": {
       "build_angle_deqp_tests": true,
@@ -41,17 +30,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-try-tot-swiftshader-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "linux-swangle-try-x64": {
     "gn_args": {
       "build_angle_deqp_tests": true,
@@ -62,17 +40,6 @@
       "use_goma": true
     }
   },
-  "linux-swangle-try-x86": {
-    "gn_args": {
-      "build_angle_deqp_tests": true,
-      "dcheck_always_on": true,
-      "is_component_build": true,
-      "is_debug": false,
-      "symbol_level": 1,
-      "target_cpu": "x86",
-      "use_goma": true
-    }
-  },
   "mac-swangle-chromium-try-x64": {
     "gn_args": {
       "dcheck_always_on": true,
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9487f93..289e674 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26826,6 +26826,7 @@
       label="LANGUAGESETTINGSPRIVATE_GETALWAYSTRANSLATELANGUAGES"/>
   <int value="1545"
       label="LANGUAGESETTINGSPRIVATE_SETLANGUAGEALWAYSTRANSLATESTATE"/>
+  <int value="1546" label="ACCESSIBILITY_PRIVATE_SHOWCONFIRMATIONDIALOG"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -44164,7 +44165,6 @@
   <int value="-1596859081" label="WebAuthenticationPINSupport:enabled"/>
   <int value="-1596559650" label="max-tiles-for-interest-area"/>
   <int value="-1596489715" label="AutoScreenBrightness:enabled"/>
-  <int value="-1594964830" label="FilesCameraFolder:disabled"/>
   <int value="-1594298767" label="FullscreenToolbarReveal:enabled"/>
   <int value="-1588702520" label="WebOTPCrossDevice:disabled"/>
   <int value="-1586642651" label="MaterialDesignExtensions:disabled"/>
@@ -47036,7 +47036,6 @@
   <int value="1009437086" label="AutofillEnableOfferNotification:disabled"/>
   <int value="1009976778" label="SidePanel:disabled"/>
   <int value="1012942422" label="HorizontalTabSwitcherAndroid:disabled"/>
-  <int value="1014740148" label="FilesCameraFolder:enabled"/>
   <int value="1015012662" label="ChromeOSDirectVideoDecoder:enabled"/>
   <int value="1015895665" label="drop-sync-credential:enabled"/>
   <int value="1017364362" label="VrIconInDaydreamHome:enabled"/>
@@ -77322,6 +77321,9 @@
       label="Failed to load the upgraded HTTPS URL because of a net error,
              fell back to the HTTP URL."/>
   <int value="5"
+      label="Failed to load the upgraded HTTPS URL within the timeout, fell
+             back to the HTTP URL."/>
+  <int value="6"
       label="Received a redirect. This doesn't necessarily imply that the
              HTTPS load succeeded or failed."/>
 </enum>
diff --git a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
index c4f6031..89abeec9a 100644
--- a/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/compositing/histograms.xml
@@ -580,6 +580,33 @@
   </summary>
 </histogram>
 
+<histogram name="Compositing.SurfaceAggregator.CopiedSurfaceCount"
+    units="surfaces" expires_after="2021-09-05">
+  <owner>kylechar@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
+  <summary>
+    The number of surfaces where the active CompositorFrame was copied into the
+    AggregateFrame during surface aggregation. This is logged once per frame.
+  </summary>
+</histogram>
+
+<histogram name="Compositing.SurfaceAggregator.CopyUs" units="microseconds"
+    expires_after="2021-09-05">
+  <owner>kylechar@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
+  <summary>
+    Time spent copying quads during surface aggregation. This is a subset of the
+    time recorded for Compositing.SurfaceAggregator.AggregateUs and is logged
+    once per frame.
+
+    Warning: This metric may include reports from clients with low-resolution
+    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
+    will cause this metric to have an abnormal distribution. When considering
+    revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
+    solution.
+  </summary>
+</histogram>
+
 <histogram name="Compositing.SurfaceAggregator.FrameContainsVideo"
     enum="TypeOfVideoInFrame" expires_after="2021-08-01">
   <owner>vikassoni@chromium.org</owner>
@@ -591,6 +618,33 @@
   </summary>
 </histogram>
 
+<histogram name="Compositing.SurfaceAggregator.PrewalkedSurfaceCount"
+    units="surfaces" expires_after="2021-09-05">
+  <owner>kylechar@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
+  <summary>
+    The number of surfaces that were looked at during the prewalk phase of
+    surface aggregation. This is logged once per frame.
+  </summary>
+</histogram>
+
+<histogram name="Compositing.SurfaceAggregator.PrewalkUs" units="microseconds"
+    expires_after="2021-09-05">
+  <owner>kylechar@chromium.org</owner>
+  <owner>jonross@chromium.org</owner>
+  <summary>
+    Time spent doing prewalk during surface aggregation. This is a subset of the
+    time recorded for Compositing.SurfaceAggregator.AggregateUs and is logged
+    once per frame.
+
+    Warning: This metric may include reports from clients with low-resolution
+    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
+    will cause this metric to have an abnormal distribution. When considering
+    revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
+    solution.
+  </summary>
+</histogram>
+
 <histogram name="Compositing.SurfaceDependencyDeadline.Duration" units="ms"
     expires_after="2020-12-01">
   <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index f912fe81..e57f1a2 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -16370,11 +16370,14 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="SafeBrowsing_V4Store_Metrics" separator=".">
+  <suffix name="CertCsdDownloadAllowlist" label=""/>
   <suffix name="CertCsdDownloadWhitelist" label=""/>
   <suffix name="ChromeExtMalware" label=""/>
   <suffix name="ChromeUrlClientIncident" label=""/>
   <suffix name="IpMalware" label=""/>
   <suffix name="UrlBilling" label=""/>
+  <suffix name="UrlCsdAllowlist" label=""/>
+  <suffix name="UrlCsdDownloadAllowlist" label=""/>
   <suffix name="UrlCsdDownloadWhitelist" label=""/>
   <suffix name="UrlCsdWhitelist" label=""/>
   <suffix name="UrlHighConfidenceAllowlist" label=""/>
@@ -19902,6 +19905,7 @@
   <suffix name="Help" label="Help"/>
   <suffix name="Media" label="Media"/>
   <suffix name="OSSettings" label="OS Settings"/>
+  <suffix name="Personalization" label="Personalization"/>
   <suffix name="PrintManagement" label="PrintManagement"/>
   <suffix name="Sample" label="Sample"/>
   <suffix name="Scanning" label="Scanning"/>
diff --git a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
index db56a08c..25e743d2 100644
--- a/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/safe_browsing/histograms.xml
@@ -40,6 +40,22 @@
   <variant name="StandardProtection" summary="standard protection"/>
 </variants>
 
+<variants name="V4StoreNewFileNames">
+  <variant name="CertCsdDownloadAllowlist"
+      summary="certificate allowlist on downloads"/>
+  <variant name="UrlCsdAllowlist"
+      summary="url allowlist on client side phishing detection"/>
+  <variant name="UrlCsdDownloadAllowlist" summary="url allowlist on downloads"/>
+</variants>
+
+<variants name="V4StoreOldFileNames">
+  <variant name="CertCsdDownloadWhitelist"
+      summary="certificate allowlist on downloads"/>
+  <variant name="UrlCsdDownloadWhitelist" summary="url allowlist on downloads"/>
+  <variant name="UrlCsdWhitelist"
+      summary="url allowlist on client side phishing detection"/>
+</variants>
+
 <histogram name="SafeBrowsing.AdvancedProtection.APTokenFetchStatus"
     enum="GoogleServiceAuthError" expires_after="2021-07-18">
   <owner>drubery@chromium.org</owner>
@@ -1641,6 +1657,58 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.V4Store.NewFileNameExists.{NewFileNames}"
+    enum="Boolean" expires_after="2021-09-09">
+  <owner>bhatiarohit@google.com</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Safe Browsing store files are being renamed from offensive to inclusive
+    names. This metric records if the new named file exists for {NewFileNames},
+    while attempting to rename it. Logged on browser startup as SafeBrowsing
+    service is initialized, and if the old file exists.
+  </summary>
+  <token key="NewFileNames" variants="V4StoreNewFileNames"/>
+</histogram>
+
+<histogram name="SafeBrowsing.V4Store.OldFileNameExists.{OldFileNames}"
+    enum="Boolean" expires_after="2021-09-09">
+  <owner>bhatiarohit@google.com</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Safe Browsing store files are being renamed from offensive to inclusive
+    names. This metric records if the old named file exists for {OldFileNames},
+    while attempting to rename it. Logged on browser startup as SafeBrowsing
+    service is initialized.
+  </summary>
+  <token key="OldFileNames" variants="V4StoreOldFileNames"/>
+</histogram>
+
+<histogram name="SafeBrowsing.V4Store.OldFileNameInUse.{OldFileNames}"
+    enum="Boolean" expires_after="2021-09-09">
+  <owner>bhatiarohit@google.com</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Safe Browsing store files are being renamed from offensive to inclusive
+    names. This metric records if the old name is still being used for
+    {OldFileNames} store file, while attempting to rename it. This should never
+    be true. Logged on browser startup as SafeBrowsing service is initialized.
+  </summary>
+  <token key="OldFileNames" variants="V4StoreOldFileNames"/>
+</histogram>
+
+<histogram name="SafeBrowsing.V4Store.RenameStatus.{NewFileNames}"
+    enum="PlatformFileError" expires_after="2021-09-09">
+  <owner>bhatiarohit@google.com</owner>
+  <owner>chrome-safebrowsing-alerts@google.com</owner>
+  <summary>
+    Safe Browsing store files are being renamed from offensive to inclusive
+    names. This metric records the return status while renaming old store file
+    of {NewFileNames}. Logged on browser startup as SafeBrowsing service is
+    initialized, and if the old file exists and the new one does not.
+  </summary>
+  <token key="NewFileNames" variants="V4StoreNewFileNames"/>
+</histogram>
+
 <histogram name="SafeBrowsing.V4StoreRead.Result"
     enum="SafeBrowsingV4StoreReadResult" expires_after="2021-07-30">
   <owner>vakh@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
index 913f78b6..4b0b540a 100644
--- a/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/sharing/histograms.xml
@@ -508,6 +508,18 @@
   </summary>
 </histogram>
 
+<histogram name="Sharing.SmsFetcherTapWithChromeDestroyed" enum="Boolean"
+    expires_after="M96">
+  <owner>yigu@chromium.org</owner>
+  <owner>web-identity@google.com</owner>
+  <summary>
+    Records whether a user taps/dismisses the notification after Chrome is
+    destroyed. This could happen if the user manually swipes away Chrome from
+    the task switcher or the OS decides to destroy Chrome due to lack of memory
+    etc. This is logged once per user action on the notification.
+  </summary>
+</histogram>
+
 <histogram name="Sharing.WebRtc.IceConfigFetched" units="ice_servers"
     expires_after="M88">
   <owner>himanshujaju@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/OWNERS b/tools/perf/core/perfetto_binary_roller/OWNERS
index 9c41def..84cf76f 100644
--- a/tools/perf/core/perfetto_binary_roller/OWNERS
+++ b/tools/perf/core/perfetto_binary_roller/OWNERS
@@ -1,3 +1,5 @@
 khokhlov@google.com
 dproy@google.com
 skyostil@google.com
+
+per-file binary_deps.json=chromium-autoroll@skia-public.iam.gserviceaccount.com
diff --git a/tools/style_variable_generator/base_generator.py b/tools/style_variable_generator/base_generator.py
index a4fb805..a0d74c6 100644
--- a/tools/style_variable_generator/base_generator.py
+++ b/tools/style_variable_generator/base_generator.py
@@ -276,15 +276,15 @@
                 raise ValueError("Color %s not defined for default mode" % name)
             for mode, color in mode_values.items():
                 if color.var:
-                    CheckColorReference(color.var, color)
+                    CheckColorReference(color.var, name)
                 if color.rgb_var:
-                    CheckColorReference(color.RGBVarToVar(), color)
+                    CheckColorReference(color.RGBVarToVar(), name)
                 if color.opacity and color.opacity.var:
-                    CheckOpacityReference(color.opacity.var, color)
+                    CheckOpacityReference(color.opacity.var, name)
 
         for name, mode_values in opacities.items():
             for mode, opacity in mode_values.items():
                 if opacity.var:
-                    CheckOpacityReference(opacity.var)
+                    CheckOpacityReference(opacity.var, name)
 
         # TODO(calamity): Check for circular references.
diff --git a/tools/style_variable_generator/colors_test.json5 b/tools/style_variable_generator/colors_test.json5
index a78e0092..9c888cc6 100644
--- a/tools/style_variable_generator/colors_test.json5
+++ b/tools/style_variable_generator/colors_test.json5
@@ -20,5 +20,9 @@
   },
   opacities: {
     disabled_opacity: 0.38,
+    reference_opacity: {
+        light: '$disabled_opacity',
+        dark: 1,
+    },
   },
 }
diff --git a/tools/style_variable_generator/colors_test_dark_only_expected.css b/tools/style_variable_generator/colors_test_dark_only_expected.css
index 5f3371b..5e1903b 100644
--- a/tools/style_variable_generator/colors_test_dark_only_expected.css
+++ b/tools/style_variable_generator/colors_test_dark_only_expected.css
@@ -18,4 +18,6 @@
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
 
   --cros-disabled-opacity: 0.38;
+
+  --cros-reference-opacity: var(--cros-disabled-opacity);
 }
diff --git a/tools/style_variable_generator/colors_test_expected.css b/tools/style_variable_generator/colors_test_expected.css
index eb412344..2ffc6df 100644
--- a/tools/style_variable_generator/colors_test_expected.css
+++ b/tools/style_variable_generator/colors_test_expected.css
@@ -18,6 +18,8 @@
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), 0.1);
 
   --cros-disabled-opacity: 0.38;
+
+  --cros-reference-opacity: var(--cros-disabled-opacity);
 }
 
 @media (prefers-color-scheme: dark) {
@@ -27,5 +29,7 @@
 
   --cros-toggle-color-rgb: var(--cros-text-color-primary-rgb);
   --cros-toggle-color: rgba(var(--cros-toggle-color-rgb), var(--cros-disabled-opacity));
+
+  --cros-reference-opacity: 1;
 }
 }
diff --git a/tools/style_variable_generator/colors_test_expected.h b/tools/style_variable_generator/colors_test_expected.h
index df8573c..70d4191 100644
--- a/tools/style_variable_generator/colors_test_expected.h
+++ b/tools/style_variable_generator/colors_test_expected.h
@@ -19,12 +19,19 @@
 
 enum class OpacityName {
   kDisabledOpacity,
+  kReferenceOpacity,
 };
 
 constexpr SkAlpha GetOpacity(OpacityName opacity_name, bool is_dark_mode) {
   switch (opacity_name) {
     case OpacityName::kDisabledOpacity:
       return 0x60;
+    case OpacityName::kReferenceOpacity:
+      if (is_dark_mode) {
+        return 0xFF;
+      } else {
+        return GetOpacity(OpacityName::kDisabledOpacity, is_dark_mode);
+      }
   }
 }
 
diff --git a/tools/style_variable_generator/css_generator.py b/tools/style_variable_generator/css_generator.py
index 2abcb52..293cdad 100644
--- a/tools/style_variable_generator/css_generator.py
+++ b/tools/style_variable_generator/css_generator.py
@@ -37,6 +37,7 @@
         return {
             'to_css_var_name': self._ToCSSVarName,
             'css_color': self._CSSColor,
+            'css_opacity': self._CSSOpacity,
             'css_color_rgb': self._CSSColorRGB,
         }
 
diff --git a/tools/style_variable_generator/css_generator.tmpl b/tools/style_variable_generator/css_generator.tmpl
index 1f9f820..824363a 100644
--- a/tools/style_variable_generator/css_generator.tmpl
+++ b/tools/style_variable_generator/css_generator.tmpl
@@ -14,7 +14,7 @@
 {% endfor %}
 
 {%- for name, value in opacities[mode].items() %}
-  {{name | to_css_var_name}}: {{value}};
+  {{name | to_css_var_name}}: {{value | css_opacity}};
 {%  endfor -%}
 {%- endmacro %}
 {#
diff --git a/tools/style_variable_generator/views_generator.py b/tools/style_variable_generator/views_generator.py
index 28eb5ce..4e98d64 100644
--- a/tools/style_variable_generator/views_generator.py
+++ b/tools/style_variable_generator/views_generator.py
@@ -30,6 +30,7 @@
             'to_const_name': self._ToConstName,
             'cpp_color': self._CppColor,
             'alpha_to_hex': self._AlphaToHex,
+            'cpp_opacity': self._CppOpacity,
         }
 
     def GetGlobals(self):
@@ -58,18 +59,18 @@
     def _AlphaToHex(self, opacity):
         return '0x%X' % math.floor(opacity.a * 255)
 
+    def _CppOpacity(self, opacity):
+        if opacity.a != -1:
+            return self._AlphaToHex(opacity)
+        elif opacity.var:
+            return ('GetOpacity(OpacityName::%s, is_dark_mode)' %
+                    self._ToConstName(opacity.var))
+        raise ValueError('Invalid opacity: ' + repr(opacity))
+
     def _CppColor(self, c):
         '''Returns the C++ color representation of |c|'''
         assert (isinstance(c, Color))
 
-        def CppOpacity(color):
-            if c.opacity.a != -1:
-                return self._AlphaToHex(c.opacity)
-            elif c.opacity.var:
-                return ('GetOpacity(OpacityName::%s, is_dark_mode)' %
-                    self._ToConstName(c.opacity.var))
-            raise ValueError('Color with invalid opacity: ' + repr(color))
-
         if c.var:
             return ('ResolveColor(ColorName::%s, is_dark_mode)' %
                     self._ToConstName(c.var))
@@ -77,10 +78,11 @@
         if c.rgb_var:
             return (
                 'SkColorSetA(ResolveColor(ColorName::%s, is_dark_mode), %s)' %
-                (self._ToConstName(c.RGBVarToVar()), CppOpacity(c)))
+                (self._ToConstName(c.RGBVarToVar()), self._CppOpacity(
+                    c.opacity)))
 
         if c.opacity.a != 1:
-            return 'SkColorSetARGB(%s, 0x%X, 0x%X, 0x%X)' % (CppOpacity(c),
-                                                             c.r, c.g, c.b)
+            return 'SkColorSetARGB(%s, 0x%X, 0x%X, 0x%X)' % (self._CppOpacity(
+                c.opacity), c.r, c.g, c.b)
         else:
             return 'SkColorSetRGB(0x%X, 0x%X, 0x%X)' % (c.r, c.g, c.b)
diff --git a/tools/style_variable_generator/views_generator_h.tmpl b/tools/style_variable_generator/views_generator_h.tmpl
index d8a67c6..8050cab8 100644
--- a/tools/style_variable_generator/views_generator_h.tmpl
+++ b/tools/style_variable_generator/views_generator_h.tmpl
@@ -36,12 +36,12 @@
     case OpacityName::{{name | to_const_name}}:
 {%-   if mode_values[Modes.DARK] %}
       if (is_dark_mode) {
-        return {{mode_values[Modes.DARK] | alpha_to_hex}};
+        return {{mode_values[Modes.DARK] | cpp_opacity}};
       } else {
-        return {{mode_values[Modes.LIGHT] | alpha_to_hex}};
+        return {{mode_values[Modes.LIGHT] | cpp_opacity}};
       }
 {%-    else %}
-      return {{mode_values[Modes.LIGHT] | alpha_to_hex}};
+      return {{mode_values[Modes.LIGHT] | cpp_opacity}};
 {%-    endif %}
 {%-   endfor %}
   }
diff --git a/ui/accessibility/BUILD.gn b/ui/accessibility/BUILD.gn
index 5cb999878..b4707c3 100644
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -48,6 +48,8 @@
     "ax_action_handler.h",
     "ax_action_handler_base.cc",
     "ax_action_handler_base.h",
+    "ax_action_handler_registry.cc",
+    "ax_action_handler_registry.h",
     "ax_base_export.h",
     "ax_enum_util.cc",
     "ax_enum_util.h",
@@ -69,8 +71,6 @@
     "ax_tree_data.h",
     "ax_tree_id.cc",
     "ax_tree_id.h",
-    "ax_tree_id_registry.cc",
-    "ax_tree_id_registry.h",
     "ax_tree_update.cc",
     "ax_tree_update.h",
     "ax_tree_update_forward.h",
diff --git a/ui/accessibility/ax_action_handler.cc b/ui/accessibility/ax_action_handler.cc
index 3ac9ce8..6affa11ab 100644
--- a/ui/accessibility/ax_action_handler.cc
+++ b/ui/accessibility/ax_action_handler.cc
@@ -4,12 +4,12 @@
 
 #include "ui/accessibility/ax_action_handler.h"
 
-#include "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 
 namespace ui {
 
 AXActionHandler::AXActionHandler()
     : AXActionHandlerBase(
-          AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID(this)) {}
+          AXActionHandlerRegistry::GetInstance()->GetOrCreateAXTreeID(this)) {}
 
 }  // namespace ui
diff --git a/ui/accessibility/ax_action_handler.h b/ui/accessibility/ax_action_handler.h
index 0b7cdf6..03d3c03 100644
--- a/ui/accessibility/ax_action_handler.h
+++ b/ui/accessibility/ax_action_handler.h
@@ -12,7 +12,8 @@
 
 // The class you normally want to inherit from other classes when you want to
 // make them visible to accessibility clients, since it automatically registers
-// a valid AXTreeID with the AXTreeIDRegistry when constructing the instance.
+// a valid AXTreeID with the AXActionHandlerRegistry when constructing the
+// instance.
 //
 // If you need more control over how the AXTreeID associated to this class is
 // set, please inherit directly from AXActionHandlerBase instead.
diff --git a/ui/accessibility/ax_action_handler_base.cc b/ui/accessibility/ax_action_handler_base.cc
index 43edc1e2..58e571d3 100644
--- a/ui/accessibility/ax_action_handler_base.cc
+++ b/ui/accessibility/ax_action_handler_base.cc
@@ -4,7 +4,7 @@
 
 #include "ui/accessibility/ax_action_handler_base.h"
 
-#include "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 
 namespace ui {
 
@@ -19,14 +19,14 @@
     : tree_id_(ax_tree_id) {}
 
 AXActionHandlerBase::~AXActionHandlerBase() {
-  AXTreeIDRegistry::GetInstance()->RemoveAXTreeID(tree_id_);
+  AXActionHandlerRegistry::GetInstance()->RemoveAXTreeID(tree_id_);
 }
 
 void AXActionHandlerBase::SetAXTreeID(AXTreeID new_ax_tree_id) {
   DCHECK_NE(new_ax_tree_id, ui::AXTreeIDUnknown());
-  AXTreeIDRegistry::GetInstance()->RemoveAXTreeID(tree_id_);
+  AXActionHandlerRegistry::GetInstance()->RemoveAXTreeID(tree_id_);
   tree_id_ = new_ax_tree_id;
-  AXTreeIDRegistry::GetInstance()->SetAXTreeID(tree_id_, this);
+  AXActionHandlerRegistry::GetInstance()->SetAXTreeID(tree_id_, this);
 }
 
 }  // namespace ui
diff --git a/ui/accessibility/ax_action_handler_base.h b/ui/accessibility/ax_action_handler_base.h
index ee2522e..93ce3a23 100644
--- a/ui/accessibility/ax_action_handler_base.h
+++ b/ui/accessibility/ax_action_handler_base.h
@@ -47,7 +47,7 @@
   void SetAXTreeID(AXTreeID new_ax_tree_id);
 
  private:
-  // Register or unregister this class with |AXTreeIDRegistry|.
+  // Register or unregister this class with |AXActionHandlerRegistry|.
   void UpdateActiveState(bool active);
 
   // Manually set in this base class, but automatically set by instances of the
diff --git a/ui/accessibility/ax_tree_id_registry.cc b/ui/accessibility/ax_action_handler_registry.cc
similarity index 64%
rename from ui/accessibility/ax_tree_id_registry.cc
rename to ui/accessibility/ax_action_handler_registry.cc
index ca706c3d..19cf7d6c 100644
--- a/ui/accessibility/ax_tree_id_registry.cc
+++ b/ui/accessibility/ax_action_handler_registry.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 "ui/accessibility/ax_tree_id_registry.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 
 #include "base/memory/singleton.h"
 #include "base/strings/string_number_conversions.h"
@@ -11,12 +11,13 @@
 namespace ui {
 
 // static
-AXTreeIDRegistry* AXTreeIDRegistry::GetInstance() {
-  return base::Singleton<AXTreeIDRegistry>::get();
+AXActionHandlerRegistry* AXActionHandlerRegistry::GetInstance() {
+  return base::Singleton<AXActionHandlerRegistry>::get();
 }
 
-void AXTreeIDRegistry::SetFrameIDForAXTreeID(const FrameID& frame_id,
-                                             const AXTreeID& ax_tree_id) {
+void AXActionHandlerRegistry::SetFrameIDForAXTreeID(
+    const FrameID& frame_id,
+    const AXTreeID& ax_tree_id) {
   auto it = frame_to_ax_tree_id_map_.find(frame_id);
   if (it != frame_to_ax_tree_id_map_.end()) {
     NOTREACHED();
@@ -27,7 +28,7 @@
   ax_tree_to_frame_id_map_[ax_tree_id] = frame_id;
 }
 
-AXTreeIDRegistry::FrameID AXTreeIDRegistry::GetFrameID(
+AXActionHandlerRegistry::FrameID AXActionHandlerRegistry::GetFrameID(
     const AXTreeID& ax_tree_id) {
   auto it = ax_tree_to_frame_id_map_.find(ax_tree_id);
   if (it != ax_tree_to_frame_id_map_.end())
@@ -36,7 +37,8 @@
   return FrameID(-1, -1);
 }
 
-AXTreeID AXTreeIDRegistry::GetAXTreeID(AXTreeIDRegistry::FrameID frame_id) {
+AXTreeID AXActionHandlerRegistry::GetAXTreeID(
+    AXActionHandlerRegistry::FrameID frame_id) {
   auto it = frame_to_ax_tree_id_map_.find(frame_id);
   if (it != frame_to_ax_tree_id_map_.end())
     return it->second;
@@ -44,7 +46,8 @@
   return ui::AXTreeIDUnknown();
 }
 
-AXTreeID AXTreeIDRegistry::GetOrCreateAXTreeID(AXActionHandlerBase* handler) {
+AXTreeID AXActionHandlerRegistry::GetOrCreateAXTreeID(
+    AXActionHandlerBase* handler) {
   for (auto it : id_to_action_handler_) {
     if (it.second == handler)
       return it.first;
@@ -54,20 +57,21 @@
   return new_id;
 }
 
-AXActionHandlerBase* AXTreeIDRegistry::GetActionHandler(AXTreeID ax_tree_id) {
+AXActionHandlerBase* AXActionHandlerRegistry::GetActionHandler(
+    AXTreeID ax_tree_id) {
   auto it = id_to_action_handler_.find(ax_tree_id);
   if (it == id_to_action_handler_.end())
     return nullptr;
   return it->second;
 }
 
-void AXTreeIDRegistry::SetAXTreeID(const ui::AXTreeID& id,
-                                   AXActionHandlerBase* action_handler) {
+void AXActionHandlerRegistry::SetAXTreeID(const ui::AXTreeID& id,
+                                          AXActionHandlerBase* action_handler) {
   DCHECK(id_to_action_handler_.find(id) == id_to_action_handler_.end());
   id_to_action_handler_[id] = action_handler;
 }
 
-void AXTreeIDRegistry::RemoveAXTreeID(AXTreeID ax_tree_id) {
+void AXActionHandlerRegistry::RemoveAXTreeID(AXTreeID ax_tree_id) {
   auto frame_it = ax_tree_to_frame_id_map_.find(ax_tree_id);
   if (frame_it != ax_tree_to_frame_id_map_.end()) {
     frame_to_ax_tree_id_map_.erase(frame_it->second);
@@ -79,9 +83,8 @@
     id_to_action_handler_.erase(action_it);
 }
 
-AXTreeIDRegistry::AXTreeIDRegistry() {
-}
+AXActionHandlerRegistry::AXActionHandlerRegistry() {}
 
-AXTreeIDRegistry::~AXTreeIDRegistry() {}
+AXActionHandlerRegistry::~AXActionHandlerRegistry() {}
 
 }  // namespace ui
diff --git a/ui/accessibility/ax_tree_id_registry.h b/ui/accessibility/ax_action_handler_registry.h
similarity index 83%
rename from ui/accessibility/ax_tree_id_registry.h
rename to ui/accessibility/ax_action_handler_registry.h
index f597ed6..b11a9a0 100644
--- a/ui/accessibility/ax_tree_id_registry.h
+++ b/ui/accessibility/ax_action_handler_registry.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 UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
-#define UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
+#ifndef UI_ACCESSIBILITY_AX_ACTION_HANDLER_REGISTRY_H_
+#define UI_ACCESSIBILITY_AX_ACTION_HANDLER_REGISTRY_H_
 
 #include <map>
 #include <string>
@@ -31,12 +31,12 @@
 // The first form allows underlying instances to change but refer to the same
 // frame.
 // The second form allows this registry to track the object for later retrieval.
-class AX_BASE_EXPORT AXTreeIDRegistry {
+class AX_BASE_EXPORT AXActionHandlerRegistry {
  public:
   using FrameID = std::pair<int, int>;
 
   // Get the single instance of this class.
-  static AXTreeIDRegistry* GetInstance();
+  static AXActionHandlerRegistry* GetInstance();
 
   // Gets the frame id based on an ax tree id.
   FrameID GetFrameID(const AXTreeID& ax_tree_id);
@@ -56,7 +56,7 @@
                              const AXTreeID& ax_tree_id);
 
  private:
-  friend struct base::DefaultSingletonTraits<AXTreeIDRegistry>;
+  friend struct base::DefaultSingletonTraits<AXActionHandlerRegistry>;
   friend AXActionHandler;
   friend AXActionHandlerBase;
 
@@ -67,8 +67,8 @@
   void SetAXTreeID(const AXTreeID& ax_tree_id,
                    AXActionHandlerBase* action_handler);
 
-  AXTreeIDRegistry();
-  virtual ~AXTreeIDRegistry();
+  AXActionHandlerRegistry();
+  virtual ~AXActionHandlerRegistry();
 
   // Maps an accessibility tree to its frame via ids.
   std::map<AXTreeID, FrameID> ax_tree_to_frame_id_map_;
@@ -79,9 +79,9 @@
   // Maps an id to its handler.
   std::map<AXTreeID, AXActionHandlerBase*> id_to_action_handler_;
 
-  DISALLOW_COPY_AND_ASSIGN(AXTreeIDRegistry);
+  DISALLOW_COPY_AND_ASSIGN(AXActionHandlerRegistry);
 };
 
 }  // namespace ui
 
-#endif  // UI_ACCESSIBILITY_AX_TREE_ID_REGISTRY_H_
+#endif  // UI_ACCESSIBILITY_AX_ACTION_HANDLER_REGISTRY_H_
diff --git a/ui/accessibility/ax_tree_combiner.h b/ui/accessibility/ax_tree_combiner.h
index 3fc2b88..b3ee96e 100644
--- a/ui/accessibility/ax_tree_combiner.h
+++ b/ui/accessibility/ax_tree_combiner.h
@@ -7,8 +7,8 @@
 
 #include <vector>
 
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_export.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/ax_tree_update.h"
 
 namespace ui {
diff --git a/ui/accessibility/ax_tree_data.h b/ui/accessibility/ax_tree_data.h
index 01d0e67..66bbaee 100644
--- a/ui/accessibility/ax_tree_data.h
+++ b/ui/accessibility/ax_tree_data.h
@@ -13,10 +13,10 @@
 
 #include "base/optional.h"
 #include "base/strings/string_split.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_base_export.h"
 #include "ui/accessibility/ax_enums.mojom-forward.h"
 #include "ui/accessibility/ax_node_data.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace ui {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 91fd29b23..07345de 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -36,6 +36,7 @@
 #include "ui/accessibility/accessibility_features.h"
 #include "ui/accessibility/accessibility_switches.h"
 #include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_action_handler_registry.h"
 #include "ui/accessibility/ax_active_popup.h"
 #include "ui/accessibility/ax_constants.mojom.h"
 #include "ui/accessibility/ax_enum_util.h"
@@ -44,7 +45,6 @@
 #include "ui/accessibility/ax_node_position.h"
 #include "ui/accessibility/ax_role_properties.h"
 #include "ui/accessibility/ax_tree_data.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/platform/ax_fragment_root_win.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate_utils_win.h"
@@ -3960,8 +3960,8 @@
   AXTreeID tree_id = GetDelegate()->GetTreeData().tree_id;
   if (data.GetIntAttribute(ax::mojom::IntAttribute::kDOMNodeId, &dom_id) &&
       tree_id != AXTreeIDUnknown()) {
-    AXTreeIDRegistry::FrameID frame_id =
-        AXTreeIDRegistry::GetInstance()->GetFrameID(tree_id);
+    AXActionHandlerRegistry::FrameID frame_id =
+        AXActionHandlerRegistry::GetInstance()->GetFrameID(tree_id);
     runtime_id[1] = frame_id.first;
     runtime_id[2] = frame_id.second;
     runtime_id[3] = dom_id;
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index ad00a4d..44655ab 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -289,6 +289,7 @@
     "java/src/org/chromium/ui/drawable/AnimationLooper.java",
     "java/src/org/chromium/ui/drawable/StateListDrawableBuilder.java",
     "java/src/org/chromium/ui/events/devices/InputDeviceObserver.java",
+    "java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java",
     "java/src/org/chromium/ui/gfx/Animation.java",
     "java/src/org/chromium/ui/gfx/BitmapHelper.java",
     "java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java",
diff --git a/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java b/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java
new file mode 100644
index 0000000..592d891
--- /dev/null
+++ b/ui/android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java
@@ -0,0 +1,89 @@
+// 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.
+
+package org.chromium.ui.gfx;
+
+import android.annotation.SuppressLint;
+
+import androidx.annotation.Nullable;
+
+import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+import java.lang.reflect.Method;
+
+@JNINamespace("gfx")
+class AdpfRenderingStageScheduler {
+    private static final String TAG = "Adpf";
+    private static final String HINT_SERVICE = "hint";
+
+    // TODO(crbug.com/1157620): Remove reflection once SDK is public.
+    private static final boolean sEnabled;
+    private static Method sHintManagerCreateHintSession;
+    private static Method sHintSessionUpdateTargetWorkDuration;
+    private static Method sHintSessionReportActualWorkDuration;
+    private static Method sHintSessionClose;
+
+    static {
+        boolean enabled = false;
+        if (BuildInfo.isAtLeastS()) {
+            try {
+                Class hintManagerClazz = Class.forName("android.os.HintManager");
+                sHintManagerCreateHintSession =
+                        hintManagerClazz.getMethod("createHintSession", int[].class);
+                Class hintSessionClazz = Class.forName("android.os.HintManager$Session");
+                sHintSessionUpdateTargetWorkDuration =
+                        hintSessionClazz.getMethod("updateTargetWorkDuration", long.class);
+                sHintSessionReportActualWorkDuration =
+                        hintSessionClazz.getMethod("reportActualWorkDuration", long.class);
+                sHintSessionClose = hintSessionClazz.getMethod("close");
+                enabled = true;
+            } catch (ReflectiveOperationException e) {
+                Log.d(TAG, "HintManager reflection exception", e);
+            }
+        }
+        sEnabled = enabled;
+    }
+
+    private Object mHintSession;
+
+    @SuppressLint("WrongConstant") // For using HINT_SERVICE
+    @Nullable
+    @CalledByNative
+    private static AdpfRenderingStageScheduler create(int[] threadIds, long targetDurationNanos)
+            throws ReflectiveOperationException {
+        if (!sEnabled) return null;
+        Object hintManager = ContextUtils.getApplicationContext().getSystemService(HINT_SERVICE);
+        if (hintManager == null) {
+            Log.d(TAG, "Null hint manager");
+            return null;
+        }
+        Object hintSession = sHintManagerCreateHintSession.invoke(hintManager, threadIds);
+        if (hintSession == null) {
+            Log.d(TAG, "Null hint session");
+            return null;
+        }
+        return new AdpfRenderingStageScheduler(hintSession, targetDurationNanos);
+    }
+
+    private AdpfRenderingStageScheduler(Object hintSession, long targetDurationNanos)
+            throws ReflectiveOperationException {
+        mHintSession = hintSession;
+        sHintSessionUpdateTargetWorkDuration.invoke(mHintSession, targetDurationNanos);
+    }
+
+    @CalledByNative
+    private void reportCpuCompletionTime(long durationNanos) throws ReflectiveOperationException {
+        sHintSessionReportActualWorkDuration.invoke(mHintSession, durationNanos);
+    }
+
+    @CalledByNative
+    private void destroy() throws ReflectiveOperationException {
+        sHintSessionClose.invoke(mHintSession);
+        mHintSession = null;
+    }
+}
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm
index 21cc21c..0effc3b 100644
--- a/ui/base/clipboard/clipboard_mac.mm
+++ b/ui/base/clipboard/clipboard_mac.mm
@@ -483,10 +483,24 @@
   // a blank image is better.
   base::scoped_nsobject<NSImage> image;
   @try {
-    image.reset([[NSImage alloc] initWithPasteboard:pasteboard]);
+    // TODO(crbug.com/1175483): remove first branch of this code when
+    // ClipboardFilenames feature flag is removed.
+    if ([[pasteboard types] containsObject:NSFilenamesPboardType]) {
+      // -[NSImage initWithPasteboard:] gets confused with copies of a single
+      // file from the Finder, so extract the path ourselves.
+      // http://crbug.com/553686
+      NSArray* paths = [pasteboard propertyListForType:NSFilenamesPboardType];
+      if ([paths count]) {
+        // If N number of files are selected from finder, choose the last one.
+        image.reset([[NSImage alloc]
+            initWithContentsOfURL:[NSURL fileURLWithPath:[paths lastObject]]]);
+      }
+    } else {
+      if (pasteboard)
+        image.reset([[NSImage alloc] initWithPasteboard:pasteboard]);
+    }
   } @catch (id exception) {
   }
-
   if (!image)
     return SkBitmap();
   if ([[image representations] count] == 0u)
diff --git a/ui/base/ime/fuchsia/keyboard_client.cc b/ui/base/ime/fuchsia/keyboard_client.cc
index d00b2d89..276c77a9 100644
--- a/ui/base/ime/fuchsia/keyboard_client.cc
+++ b/ui/base/ime/fuchsia/keyboard_client.cc
@@ -53,15 +53,13 @@
   EventType event_type;
   switch (key_event.type()) {
     case fuchsia::ui::input3::KeyEventType::PRESSED:
+    case fuchsia::ui::input3::KeyEventType::SYNC:
       event_type = ET_KEY_PRESSED;
       break;
     case fuchsia::ui::input3::KeyEventType::RELEASED:
+    case fuchsia::ui::input3::KeyEventType::CANCEL:
       event_type = ET_KEY_RELEASED;
       break;
-    case fuchsia::ui::input3::KeyEventType::SYNC:
-    case fuchsia::ui::input3::KeyEventType::CANCEL:
-      // TODO(http://fxbug.dev/69620): Add support for SYNC and CANCEL.
-      return false;
     default:
       NOTIMPLEMENTED() << "Unknown KeyEventType received: "
                        << static_cast<int>(event_type);
@@ -71,22 +69,19 @@
   // Update activation flags of modifier keys (SHIFT, ALT, etc).
   UpdateModifiers(key_event);
 
-  if (key_event.type() == fuchsia::ui::input3::KeyEventType::RELEASED)
-    return true;
-
   // Convert |key_event| to a ui::KeyEvent.
   DomCode dom_code =
       KeycodeConverter::UsbKeycodeToDomCode(static_cast<int>(key_event.key()));
-  DomKey dom_key;
-  KeyboardCode key_code;
   int flags =
       key_event.has_modifiers() ? ComputeFlagValue(key_event.modifiers()) : 0;
 
   // TODO(https://crbug.com/1187257): Use input3.KeyMeaning instead of US layout
   // as the default.
+  DomKey dom_key;
+  KeyboardCode key_code;
   if (!DomCodeToUsLayoutDomKey(dom_code, flags, &dom_key, &key_code)) {
     LOG(ERROR) << "DomCodeToUsLayoutDomKey() failed for key: "
-               << static_cast<int>(key_event.key());
+               << static_cast<uint32_t>(key_event.key());
   }
 
   ui::KeyEvent ui_key_event(event_type, key_code, dom_code, flags, dom_key,
@@ -128,7 +123,13 @@
   }
 }
 
-int KeyboardClient::ComputeFlagValue(fuchsia::ui::input3::Modifiers modifiers) {
+int KeyboardClient::ComputeFlagValue(
+    const fuchsia::ui::input3::Modifiers& modifiers) {
+  return SystemManagedModifiersToFlags(modifiers) | LocalModifiersToFlags();
+}
+
+int KeyboardClient::SystemManagedModifiersToFlags(
+    const fuchsia::ui::input3::Modifiers& modifiers) {
   int flags = 0;
   if ((modifiers & fuchsia::ui::input3::Modifiers::CAPS_LOCK) ==
       fuchsia::ui::input3::Modifiers::CAPS_LOCK) {
@@ -142,13 +143,17 @@
       fuchsia::ui::input3::Modifiers::SCROLL_LOCK) {
     flags |= EF_SCROLL_LOCK_ON;
   }
+  return flags;
+}
+
+int KeyboardClient::LocalModifiersToFlags() {
+  int flags = 0;
   if (left_shift_ || right_shift_)
     flags |= EF_SHIFT_DOWN;
   if (left_alt_ || right_alt_)
     flags |= EF_ALT_DOWN;
   if (left_ctrl_ || right_ctrl_)
     flags |= EF_CONTROL_DOWN;
-
   return flags;
 }
 
diff --git a/ui/base/ime/fuchsia/keyboard_client.h b/ui/base/ime/fuchsia/keyboard_client.h
index ff4c1a0..9a995c3 100644
--- a/ui/base/ime/fuchsia/keyboard_client.h
+++ b/ui/base/ime/fuchsia/keyboard_client.h
@@ -20,7 +20,7 @@
 class COMPONENT_EXPORT(UI_BASE_IME_FUCHSIA) KeyboardClient
     : public fuchsia::ui::input3::KeyboardListener {
  public:
-  // |event_sink| must outlive |this|.
+  // |keyboard_service| and |event_sink| must outlive |this|.
   KeyboardClient(fuchsia::ui::input3::Keyboard* keyboard_service,
                  fuchsia::ui::views::ViewRef view_ref,
                  InputEventSink* event_sink);
@@ -42,7 +42,16 @@
 
   // Computes the ui EventFlags value based on key modifiers and current keys
   // that are held down.
-  int ComputeFlagValue(fuchsia::ui::input3::Modifiers modifiers);
+  int ComputeFlagValue(const fuchsia::ui::input3::Modifiers& modifiers);
+
+  // Converts the state of modifiers managed by Fuchsia (e.g. Caps and Num Lock)
+  // into flags.
+  int SystemManagedModifiersToFlags(
+      const fuchsia::ui::input3::Modifiers& modifiers);
+
+  // Translate state of locally tracked modifier keys (e.g. shift, alt) into
+  // flags.
+  int LocalModifiersToFlags();
 
   // fuchsia::ui::input3::KeyboardListener implementation.
   void OnKeyEvent(
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index b685e92..9a3b690 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -37,7 +37,6 @@
   deps = [
     "audio_player/elements:closure_compile",
     "audio_player/js:closure_compile",
-    "base/js:closure_compile",
     "file_manager/background/js:closure_compile",
     "file_manager/common/js:closure_compile",
     "file_manager/cws_widget:closure_compile",
@@ -58,7 +57,6 @@
 group("unit_test_data") {
   testonly = true
   deps = [
-    "base/js:js_test_gen_html",
     "file_manager/background/js:js_test_gen_html_modules",
     "file_manager/common/js:js_test_gen_html_modules",
     "file_manager/foreground/elements:js_test_gen_html_modules",
@@ -124,26 +122,24 @@
     "audio_player/elements/control_panel.m.js",
     "audio_player/elements/repeat_button.m.js",
 
-    # Base:
-    "base/js/app_util.m.js",
-    "base/js/error_counter.m.js",
-    "base/js/filtered_volume_manager.m.js",
-    "base/js/mediasession_types.m.js",
-    "base/js/volume_manager_types.m.js",
-
     # Common:
+    "file_manager/common/js/app_util.m.js",
     "file_manager/common/js/async_util.m.js",
+    "file_manager/common/js/error_counter.m.js",
     "file_manager/common/js/file_operation_common.m.js",
     "file_manager/common/js/file_type.m.js",
     "file_manager/common/js/files_app_entry_types.m.js",
+    "file_manager/common/js/filtered_volume_manager.m.js",
     "file_manager/common/js/importer_common.m.js",
     "file_manager/common/js/lru_cache.m.js",
+    "file_manager/common/js/mediasession_types.m.js",
     "file_manager/common/js/metrics.m.js",
     "file_manager/common/js/metrics_base.m.js",
     "file_manager/common/js/progress_center_common.m.js",
     "file_manager/common/js/storage_adapter.m.js",
     "file_manager/common/js/trash.m.js",
     "file_manager/common/js/util.m.js",
+    "file_manager/common/js/volume_manager_types.m.js",
 
     # Externs:
     "file_manager/externs/background/background_base.m.js",
@@ -374,7 +370,6 @@
   deps = [
     "//ui/file_manager/audio_player/elements:elements",
     "//ui/file_manager/audio_player/js:modulize",
-    "//ui/file_manager/base/js:modulize",
     "//ui/file_manager/file_manager:gen_main_html",
     "//ui/file_manager/file_manager/background/js:modulize",
     "//ui/file_manager/file_manager/common/js:modulize",
diff --git a/ui/file_manager/audio_player/js/BUILD.gn b/ui/file_manager/audio_player/js/BUILD.gn
index 10435ad9..1f29383 100644
--- a/ui/file_manager/audio_player/js/BUILD.gn
+++ b/ui/file_manager/audio_player/js/BUILD.gn
@@ -62,9 +62,9 @@
   deps = [
     "//ui/file_manager/audio_player/elements:audio_player",
     "//ui/file_manager/audio_player/elements:track_list",
-    "//ui/file_manager/base/js:app_util",
-    "//ui/file_manager/base/js:filtered_volume_manager",
-    "//ui/file_manager/base/js:mediasession_types",
+    "//ui/file_manager/file_manager/common/js:app_util",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager",
+    "//ui/file_manager/file_manager/common/js:mediasession_types",
     "//ui/file_manager/file_manager/common/js:util",
     "//ui/file_manager/file_manager/foreground/js/metadata:content_metadata_provider",
     "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model",
@@ -77,12 +77,12 @@
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/file_manager/audio_player/elements:audio_player.m",
-    "//ui/file_manager/base/js:app_util.m",
-    "//ui/file_manager/base/js:filtered_volume_manager.m",
-    "//ui/file_manager/base/js:mediasession_types.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:app_util.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:mediasession_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/foreground/js/metadata:content_metadata_provider.m",
     "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model.m",
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index dff2d70..252c5ed3 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -6,10 +6,10 @@
 // #import '../elements/audio_player.m.js';
 // #import {dashToCamelCase} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // #import {ExternallyUnmountedEvent} from '../../file_manager/externs/volume_manager.m.js';
-// #import {FilteredVolumeManager} from '../../base/js/filtered_volume_manager.m.js';
-// #import {AllowedPaths} from '../../base/js/volume_manager_types.m.js';
-// #import {MediaSessionPlaybackState} from '../../base/js/mediasession_types.m.js';
-// #import * as appUtilWrapped from '../../base/js/app_util.m.js'; const {appUtil} = appUtilWrapped;
+// #import {FilteredVolumeManager} from '../../file_manager/common/js/filtered_volume_manager.m.js';
+// #import {AllowedPaths} from '../../file_manager/common/js/volume_manager_types.m.js';
+// #import {MediaSessionPlaybackState} from '../../file_manager/common/js/mediasession_types.m.js';
+// #import * as appUtilWrapped from '../../file_manager/common/js/app_util.m.js'; const {appUtil} = appUtilWrapped;
 // #import * as wrappedAsyncUtil from '../../file_manager/common/js/async_util.m.js'; const {AsyncUtil} = wrappedAsyncUtil;
 // #import * as wrappedUtil from '../../file_manager/common/js/util.m.js'; const {util} = wrappedUtil;
 // #import {ContentMetadataProvider} from '../../file_manager/foreground/js/metadata/content_metadata_provider.m.js';
diff --git a/ui/file_manager/audio_player/js/audio_player_scripts.js b/ui/file_manager/audio_player/js/audio_player_scripts.js
index 87db713..fc8b9c1 100644
--- a/ui/file_manager/audio_player/js/audio_player_scripts.js
+++ b/ui/file_manager/audio_player/js/audio_player_scripts.js
@@ -28,10 +28,10 @@
 // <include src="../../file_manager/common/js/async_util.js">
 // <include src="../../file_manager/common/js/file_type.js">
 // <include src="../../file_manager/common/js/util.js">
-// <include src="../../base/js/mediasession_types.js">
-// <include src="../../base/js/app_util.js">
-// <include src="../../base/js/volume_manager_types.js">
-// <include src="../../base/js/filtered_volume_manager.js">
+// <include src="../../file_manager/common/js/mediasession_types.js">
+// <include src="../../file_manager/common/js/app_util.js">
+// <include src="../../file_manager/common/js/volume_manager_types.js">
+// <include src="../../file_manager/common/js/filtered_volume_manager.js">
 
 // <include src="../../file_manager/foreground/js/metadata/content_metadata_provider.js">
 // <include src="../../file_manager/foreground/js/metadata/external_metadata_provider.js">
diff --git a/ui/file_manager/base/js/BUILD.gn b/ui/file_manager/base/js/BUILD.gn
index f446c62..e69de29 100644
--- a/ui/file_manager/base/js/BUILD.gn
+++ b/ui/file_manager/base/js/BUILD.gn
@@ -1,213 +0,0 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//third_party/closure_compiler/compile_js.gni")
-import("//third_party/closure_compiler/js_unit_tests.gni")
-import("//ui/file_manager/base/gn/js_test_gen_html.gni")
-import("//ui/webui/resources/js/cr.gni")
-import("//ui/webui/resources/tools/js_modulizer.gni")
-
-visibility = [ "//ui/file_manager/*" ]
-
-group("closure_compile") {
-  testonly = true
-  deps = [
-    ":closure_compile_jsmodules",
-    ":closure_compile_module",
-    ":js_test_gen_html_type_check_auto",
-    ":test_support_type_check",
-    ":test_support_type_check_jsmodules",
-  ]
-}
-
-js_type_check("closure_compile_jsmodules") {
-  deps = [
-    ":app_util.m",
-    ":error_counter.m",
-    ":filtered_volume_manager.m",
-    ":volume_manager_types.m",
-  ]
-
-  closure_flags = strict_error_checking_closure_args + [
-                    "js_module_root=./gen/ui/",
-                    "js_module_root=../../ui/",
-                  ]
-}
-
-js_type_check("closure_compile_module") {
-  uses_legacy_modules = true
-  deps = [
-    ":app_util",
-    ":error_counter",
-    ":filtered_volume_manager",
-  ]
-}
-
-js_type_check("test_support_type_check") {
-  testonly = true
-  deps = [
-    ":mock_chrome",
-    ":test_error_reporting",
-  ]
-}
-
-js_type_check("test_support_type_check_jsmodules") {
-  testonly = true
-  deps = [
-    ":mock_chrome.m",
-    ":test_error_reporting.m",
-  ]
-}
-
-js_library("app_util") {
-  deps = [
-    ":volume_manager_types",
-    "//ui/file_manager/file_manager/externs:volume_manager",
-  ]
-  externs_list = [
-    "//ui/file_manager/file_manager/externs/app_window_common.js",
-    "//ui/file_manager/file_manager/externs/background/background_base.js",
-  ]
-}
-
-js_library("app_util.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/base/js/app_util.m.js" ]
-  deps = [
-    "//ui/file_manager/file_manager/externs:file_manager_private",
-    "//ui/file_manager/file_manager/externs:volume_manager.m",
-    "//ui/file_manager/file_manager/externs/background:background_base.m",
-  ]
-  externs_list =
-      [ "//ui/file_manager/file_manager/externs/app_window_common.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("error_counter") {
-}
-
-js_library("error_counter.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/base/js/error_counter.m.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("filtered_volume_manager") {
-  deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
-    "//ui/file_manager/file_manager/common/js:async_util",
-    "//ui/file_manager/file_manager/common/js:files_app_entry_types",
-    "//ui/file_manager/file_manager/externs:file_manager_private",
-    "//ui/file_manager/file_manager/externs:volume_manager",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js/cr/ui:array_data_model",
-  ]
-  externs_list = [ "//ui/file_manager/file_manager/externs/background/volume_manager_factory.js" ]
-}
-
-js_library("filtered_volume_manager.m") {
-  sources =
-      [ "$root_gen_dir/ui/file_manager/base/js/filtered_volume_manager.m.js" ]
-  deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
-    "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
-    "//ui/file_manager/file_manager/externs:entry_location.m",
-    "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
-    "//ui/file_manager/file_manager/externs:volume_info.m",
-    "//ui/file_manager/file_manager/externs:volume_info_list.m",
-    "//ui/file_manager/file_manager/externs:volume_manager.m",
-    "//ui/webui/resources/js:assert.m",
-    "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js/cr:event_target.m",
-    "//ui/webui/resources/js/cr/ui:array_data_model.m",
-  ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("mock_chrome") {
-  testonly = true
-}
-
-js_library("mock_chrome.m") {
-  testonly = true
-  sources = [ "$root_gen_dir/ui/file_manager/base/js/mock_chrome.m.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("test_error_reporting") {
-  testonly = true
-  deps = [
-    # Note we allow targets depending on test_error_reporting to access
-    # webui_resource_test transitively.
-    "//ui/webui/resources/js:webui_resource_test",
-  ]
-}
-
-js_library("test_error_reporting.m") {
-  testonly = true
-  sources =
-      [ "$root_gen_dir/ui/file_manager/base/js/test_error_reporting.m.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("volume_manager_types") {
-  deps = [
-    "//ui/file_manager/file_manager/externs:file_manager_private",
-    "//ui/webui/resources/js:assert",
-  ]
-}
-
-js_unittest("volume_manager_types_unittest.m") {
-  deps = [ ":volume_manager_types.m" ]
-}
-
-js_library("volume_manager_types.m") {
-  sources =
-      [ "$root_gen_dir/ui/file_manager/base/js/volume_manager_types.m.js" ]
-
-  deps = [
-    "//ui/file_manager/file_manager/externs:file_manager_private",
-    "//ui/webui/resources/js:assert.m",
-  ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_test_gen_html("js_test_gen_html") {
-  deps = [ ":volume_manager_types_unittest.m" ]
-  js_module = true
-
-  closure_flags =
-      strict_error_checking_closure_args + [
-        "js_module_root=./gen/ui/file_manager/base/js",
-        "js_module_root=../../ui/file_manager/base/js",
-        "browser_resolver_prefix_replacements=\"chrome://test/=./\"",
-      ]
-}
-
-js_library("mediasession_types") {
-}
-
-js_library("mediasession_types.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/base/js/mediasession_types.m.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_modulizer("modulize") {
-  input_files = [
-    "app_util.js",
-    "filtered_volume_manager.js",
-    "mediasession_types.js",
-    "mock_chrome.js",
-    "test_error_reporting.js",
-    "volume_manager_types.js",
-    "error_counter.js",
-  ]
-
-  namespace_rewrites = cr_namespace_rewrites
-}
diff --git a/ui/file_manager/base/tools/modules_test.py b/ui/file_manager/base/tools/modules_test.py
index 014ea0f3..0ad7732b 100755
--- a/ui/file_manager/base/tools/modules_test.py
+++ b/ui/file_manager/base/tools/modules_test.py
@@ -54,7 +54,7 @@
             'empty_dependency_list_expected.gn')
         rule_first_line = 'js_unittest("importer_common_unittest.m") {'
         list_name = 'deps'
-        dependency_line = '    "//ui/file_manager/base/js:mock_chrome",'
+        dependency_line = '    "//ui/file_manager/file_manager/common/js:mock_chrome",'
 
         # Check: dependency list correctly updated with new dependency.
         modules.add_dependency(file_lines, rule_first_line, list_name,
@@ -74,7 +74,7 @@
             'single_line_dependency_list_expected.gn')
         rule_first_line = 'js_unittest("importer_common_unittest.m") {'
         list_name = 'deps'
-        dependency_line = '    "//ui/file_manager/base/js:mock_chrome",'
+        dependency_line = '    "//ui/file_manager/file_manager/common/js:mock_chrome",'
 
         # Check: dependency list correctly formatted and updated with new
         # dependency.
diff --git a/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn b/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn
index 6538a549..0008226 100644
--- a/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn
+++ b/ui/file_manager/base/tools/tests/empty_dependency_list_expected.gn
@@ -1,6 +1,6 @@
 
 js_unittest("importer_common_unittest.m") {
   deps = [
-    "//ui/file_manager/base/js:mock_chrome",
+    "//ui/file_manager/file_manager/common/js:mock_chrome",
   ]
 }
diff --git a/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn b/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn
index ee0eadd..ee97ecb 100644
--- a/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn
+++ b/ui/file_manager/base/tools/tests/single_line_dependency_list_expected.gn
@@ -1,7 +1,7 @@
 
 js_unittest("importer_common_unittest.m") {
   deps = [
-    "//ui/file_manager/base/js:mock_chrome",
+    "//ui/file_manager/file_manager/common/js:mock_chrome",
     ":mock_entry",
   ]
 }
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn
index 5f495469..a6d724f4 100644
--- a/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -175,7 +175,7 @@
   visibility += related_apps
   deps = [
     ":app_windows",
-    "//ui/file_manager/base/js:app_util",
+    "//ui/file_manager/file_manager/common/js:app_util",
     "//ui/file_manager/file_manager/common/js:async_util",
   ]
 }
@@ -185,7 +185,7 @@
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/app_window_wrapper.m.js" ]
   deps = [
     ":app_windows.m",
-    "//ui/file_manager/base/js:app_util.m",
+    "//ui/file_manager/file_manager/common/js:app_util.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -221,10 +221,10 @@
     ":mount_metrics",
     ":progress_center",
     ":trash",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -249,10 +249,10 @@
     ":mount_metrics.m",
     ":progress_center.m",
     ":volume_manager_factory.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:crostini.m",
@@ -280,7 +280,7 @@
     ":background.m",
     ":metrics_start.m",
     ":test_util.m",
-    "//ui/file_manager/base/js:error_counter.m",
+    "//ui/file_manager/file_manager/common/js:error_counter.m",
   ]
 }
 
@@ -314,8 +314,8 @@
 
 js_library("crostini") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:metrics",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
   ]
   externs_list =
@@ -327,7 +327,7 @@
     "$root_gen_dir/ui/file_manager/file_manager/background/js/crostini.m.js",
   ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:crostini.m",
     "//ui/webui/resources/js:assert.m",
@@ -365,8 +365,8 @@
   deps = [
     ":mock_crostini.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:crostini.m",
@@ -410,12 +410,12 @@
     ":mock_progress_center.m",
     ":mock_volume_manager.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
@@ -481,7 +481,7 @@
     ":drive_sync_handler.m",
     ":mock_progress_center.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
@@ -505,10 +505,10 @@
   deps = [
     ":import_history.m",
     ":volume_manager_factory.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
     "//ui/file_manager/file_manager/common/js:lru_cache.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:duplicate_finder.m",
     "//ui/file_manager/file_manager/externs/background:import_history.m",
@@ -523,26 +523,26 @@
     ":mock_volume_manager.m",
     ":test_import_history.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs/background:duplicate_finder.m",
   ]
 }
 
 js_library("entry_location_impl") {
-  deps = [ "//ui/file_manager/base/js:volume_manager_types" ]
+  deps = [ "//ui/file_manager/file_manager/common/js:volume_manager_types" ]
   externs_list = [ "//ui/file_manager/file_manager/externs/entry_location.js" ]
 }
 
 js_library("entry_location_impl.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/entry_location_impl.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
   ]
@@ -642,10 +642,10 @@
     ":file_operation_util.m",
     ":volume_manager_factory.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:file_operation_common.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:util.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs/background:file_operation_manager.m",
@@ -693,8 +693,8 @@
   deps = [
     ":metadata_proxy.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -732,10 +732,10 @@
   deps = [
     ":import_history.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:test_importer_common.m",
     "//ui/file_manager/file_manager/common/js:unittest_util.m",
     "//ui/file_manager/file_manager/externs/background:import_history.m",
@@ -835,12 +835,12 @@
     ":mock_volume_manager.m",
     ":test_import_history.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:test_importer_common.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs/background:duplicate_finder.m",
     "//ui/file_manager/file_manager/externs/background:import_history.m",
@@ -907,8 +907,8 @@
     ":mock_media_scanner.m",
     ":test_import_history.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:unittest_util.m",
     "//ui/file_manager/file_manager/externs/background:media_scanner.m",
   ]
@@ -934,9 +934,9 @@
     ":volume_info_list_impl.m",
     ":volume_manager_factory.m",
     ":volume_manager_impl.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
@@ -1012,7 +1012,7 @@
     ":file_operation_util",
     ":test_util_base",
     ":volume_manager_factory",
-    "//ui/file_manager/base/js:error_counter",
+    "//ui/file_manager/file_manager/common/js:error_counter",
     "//ui/file_manager/file_manager/common/js:importer_common",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:progress_center_common",
@@ -1038,16 +1038,16 @@
 }
 
 js_library("volume_info_impl") {
-  deps = [ "//ui/file_manager/base/js:volume_manager_types" ]
+  deps = [ "//ui/file_manager/file_manager/common/js:volume_manager_types" ]
   externs_list = [ "//ui/file_manager/file_manager/externs/volume_info.js" ]
 }
 
 js_library("volume_info_impl.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/volume_info_impl.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/webui/resources/js:assert.m",
@@ -1070,8 +1070,8 @@
   deps = [
     ":task_queue.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/externs/background:task_queue.m",
   ]
 }
@@ -1095,9 +1095,9 @@
   visibility += related_apps
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/test_util_base.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:assert.m",
   ]
   extra_deps = [ ":modulize" ]
@@ -1141,8 +1141,8 @@
 js_library("trash") {
   deps = [
     ":file_operation_util",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:trash",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
   ]
 }
@@ -1166,9 +1166,9 @@
     ":mock_volume_manager.m",
     ":trash.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
     "//ui/file_manager/file_manager/common/js:trash.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
@@ -1205,9 +1205,9 @@
   deps = [
     ":mount_metrics.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 }
 
@@ -1234,9 +1234,9 @@
     ":entry_location_impl.m",
     ":volume_info_list_impl.m",
     ":volume_manager_util.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
@@ -1268,10 +1268,10 @@
     ":volume_manager_impl.m",
     ":volume_manager_util.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 }
@@ -1279,9 +1279,9 @@
 js_library("volume_manager_util") {
   deps = [
     ":volume_info_impl",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -1289,8 +1289,8 @@
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/background/js/volume_manager_util.m.js" ]
   deps = [
     ":volume_info_impl.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
   ]
 
diff --git a/ui/file_manager/file_manager/background/js/app_window_wrapper.js b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
index 0897595..9a05a28 100644
--- a/ui/file_manager/file_manager/background/js/app_window_wrapper.js
+++ b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
@@ -5,7 +5,7 @@
 // clang-format off
 // #import './app_windows.m.js';
 // #import * as wrappedAsyncUtil from '../../common/js/async_util.m.js'; const {AsyncUtil} = wrappedAsyncUtil;
-// #import * as wrappedAppUtil from '../../../base/js/app_util.m.js'; const {appUtil} = wrappedAppUtil;
+// #import * as wrappedAppUtil from '../../common/js/app_util.m.js'; const {appUtil} = wrappedAppUtil;
 // #import {assertInstanceof} from 'chrome://resources/js/assert.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/background/js/background.js b/ui/file_manager/file_manager/background/js/background.js
index 5323578..5deffcd8 100644
--- a/ui/file_manager/file_manager/background/js/background.js
+++ b/ui/file_manager/file_manager/background/js/background.js
@@ -20,7 +20,7 @@
 // #import {launcher, LaunchType, nextFileManagerWindowID, FILES_ID_PATTERN} from './launcher.m.js';
 // #import {FileOperationHandler} from './file_operation_handler.m.js';
 // #import {FileOperationManagerImpl} from './file_operation_manager.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {volumeManagerFactory} from './volume_manager_factory.m.js';
 // #import {LauncherSearch} from './launcher_search.m.js';
 // #import {MountMetrics} from './mount_metrics.m.js';
diff --git a/ui/file_manager/file_manager/background/js/background_common_scripts.js b/ui/file_manager/file_manager/background/js/background_common_scripts.js
index 02e6e1d2..f10e720 100644
--- a/ui/file_manager/file_manager/background/js/background_common_scripts.js
+++ b/ui/file_manager/file_manager/background/js/background_common_scripts.js
@@ -14,12 +14,12 @@
 // <include src="../../common/js/file_type.js">
 // <include src="../../common/js/metrics_base.js">
 // <include src="../../common/js/files_app_entry_types.js">
-// <include src="../../../base/js/app_util.js">
+// <include src="../../../file_manager/common/js/app_util.js">
 
 /* TODO(tapted): Remove this when it is specific to the files app */
 // <include src="../../common/js/util.js">
 
-// <include src="../../../base/js/volume_manager_types.js">
+// <include src="../../../file_manager/common/js/volume_manager_types.js">
 // <include src="app_window_wrapper.js">
 // <include src="app_windows.js">
 // <include src="background_base.js">
diff --git a/ui/file_manager/file_manager/background/js/background_scripts.js b/ui/file_manager/file_manager/background/js/background_scripts.js
index 3313054..0888738b 100644
--- a/ui/file_manager/file_manager/background/js/background_scripts.js
+++ b/ui/file_manager/file_manager/background/js/background_scripts.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // error_counter.js must be loaded before all other scripts of the Files app.
-// <include src="../../../base/js/error_counter.js">
+// <include src="../../../file_manager/common/js/error_counter.js">
 
 // <include src="../../common/js/metrics.js">
 // <include src="metrics_start.js">
diff --git a/ui/file_manager/file_manager/background/js/crostini.js b/ui/file_manager/file_manager/background/js/crostini.js
index 06b8d37..1a10f687 100644
--- a/ui/file_manager/file_manager/background/js/crostini.js
+++ b/ui/file_manager/file_manager/background/js/crostini.js
@@ -5,7 +5,7 @@
 // clang-format off
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {Crostini} from '../../externs/background/crostini.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/background/js/crostini_unittest.m.js b/ui/file_manager/file_manager/background/js/crostini_unittest.m.js
index 93106fc..447cef84 100644
--- a/ui/file_manager/file_manager/background/js/crostini_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/crostini_unittest.m.js
@@ -6,8 +6,8 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import { assertFalse,assertTrue} from 'chrome://test/chai_assert.js';
 
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import { MockDirectoryEntry, MockEntry,MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {Crostini} from '../../externs/background/crostini.m.js';
 import {EntryLocation} from '../../externs/entry_location.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
diff --git a/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js b/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
index 3c4361918..872ce675 100644
--- a/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/device_handler_unittest.m.js
@@ -5,12 +5,12 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockChromeStorageAPI} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
 import {metrics} from '../../common/js/metrics.m.js';
+import {installMockChrome, MockChromeStorageAPI} from '../../common/js/mock_chrome.m.js';
 import {MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {VolumeInfo} from '../../externs/volume_info.m.js';
 
 import {DeviceHandler} from './device_handler.m.js';
diff --git a/ui/file_manager/file_manager/background/js/drive_sync_handler_unittest.m.js b/ui/file_manager/file_manager/background/js/drive_sync_handler_unittest.m.js
index 8739b75..58a686ed 100644
--- a/ui/file_manager/file_manager/background/js/drive_sync_handler_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/drive_sync_handler_unittest.m.js
@@ -6,7 +6,7 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertEquals,assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import {ProgressItemState} from '../../common/js/progress_center_common.m.js';
 
 import {DriveSyncHandlerImpl} from './drive_sync_handler.m.js';
diff --git a/ui/file_manager/file_manager/background/js/duplicate_finder.js b/ui/file_manager/file_manager/background/js/duplicate_finder.js
index 1f8ffcf9..aebfca0 100644
--- a/ui/file_manager/file_manager/background/js/duplicate_finder.js
+++ b/ui/file_manager/file_manager/background/js/duplicate_finder.js
@@ -8,7 +8,7 @@
  */
 
 // clang-format off
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {importerHistoryInterfaces} from '../../externs/background/import_history.m.js';
diff --git a/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.m.js b/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.m.js
index 55ce943c..d720266f 100644
--- a/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/duplicate_finder_unittest.m.js
@@ -4,11 +4,11 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {duplicateFinderInterfaces} from '../../externs/background/duplicate_finder.m.js';
 import {VolumeInfo} from '../../externs/volume_info.m.js';
 
diff --git a/ui/file_manager/file_manager/background/js/entry_location_impl.js b/ui/file_manager/file_manager/background/js/entry_location_impl.js
index bb45adc..836b097 100644
--- a/ui/file_manager/file_manager/background/js/entry_location_impl.js
+++ b/ui/file_manager/file_manager/background/js/entry_location_impl.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import * as wrappedUtil from '../../common/js/util.m.js'; const {util} = wrappedUtil;
 // #import {EntryLocation} from '../../externs/entry_location.m.js';
 // #import {VolumeInfo} from '../../externs/volume_info.m.js';
diff --git a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.m.js b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.m.js
index 8bf101fa..0e496772 100644
--- a/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/file_operation_manager_unittest.m.js
@@ -6,10 +6,10 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import { assertArrayEquals, assertEquals, assertFalse,assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise, waitUntil} from '../../../base/js/test_error_reporting.m.js';
 import {FileOperationProgressEvent} from '../../common/js/file_operation_common.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import { joinPath, MockDirectoryEntry, MockEntry, MockFileEntry,MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise, waitUntil} from '../../common/js/test_error_reporting.m.js';
 import {util} from '../../common/js/util.m.js';
 import {FileOperationManager} from '../../externs/background/file_operation_manager.m.js';
 import {EntryLocation} from '../../externs/entry_location.m.js';
diff --git a/ui/file_manager/file_manager/background/js/import_history_unittest.m.js b/ui/file_manager/file_manager/background/js/import_history_unittest.m.js
index 9fb91c1..8bbc443 100644
--- a/ui/file_manager/file_manager/background/js/import_history_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/import_history_unittest.m.js
@@ -5,10 +5,10 @@
 // clang-format off
 import { assertEquals,assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {MockChromeStorageAPI} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
+import {MockChromeStorageAPI} from '../../common/js/mock_chrome.m.js';
 import {MockFileEntry,MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 import {importerTest} from '../../common/js/test_importer_common.m.js';
 import {TestCallRecorder} from '../../common/js/unittest_util.m.js';
 import {importerHistoryInterfaces} from '../../externs/background/import_history.m.js';
diff --git a/ui/file_manager/file_manager/background/js/main_background.m.js b/ui/file_manager/file_manager/background/js/main_background.m.js
index de846b6d..bbad577a8 100644
--- a/ui/file_manager/file_manager/background/js/main_background.m.js
+++ b/ui/file_manager/file_manager/background/js/main_background.m.js
@@ -8,6 +8,6 @@
  */
 
 import './metrics_start.m.js';
-import '../../../base/js/error_counter.m.js';
+import '../../common/js/error_counter.m.js';
 import './background.m.js';
 import './test_util.m.js';
diff --git a/ui/file_manager/file_manager/background/js/media_import_handler_unittest.m.js b/ui/file_manager/file_manager/background/js/media_import_handler_unittest.m.js
index cf8eebb..c8ed10d 100644
--- a/ui/file_manager/file_manager/background/js/media_import_handler_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/media_import_handler_unittest.m.js
@@ -4,12 +4,12 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 import {importerTest} from '../../common/js/test_importer_common.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {duplicateFinderInterfaces} from '../../externs/background/duplicate_finder.m.js';
 import {importerHistoryInterfaces} from '../../externs/background/import_history.m.js';
 import {mediaImportInterfaces} from '../../externs/background/media_import_handler.m.js';
diff --git a/ui/file_manager/file_manager/background/js/media_scanner_unittest.m.js b/ui/file_manager/file_manager/background/js/media_scanner_unittest.m.js
index bfad0dd84..2ecd9f57 100644
--- a/ui/file_manager/file_manager/background/js/media_scanner_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/media_scanner_unittest.m.js
@@ -4,8 +4,8 @@
 
 import {assertEquals, assertFalse, assertThrows} from 'chrome://test/chai_assert.js';
 
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 import {assertFileEntryPathsEqual} from '../../common/js/unittest_util.m.js';
 import {mediaScannerInterfaces} from '../../externs/background/media_scanner.m.js';
 
diff --git a/ui/file_manager/file_manager/background/js/metadata_proxy_unittest.m.js b/ui/file_manager/file_manager/background/js/metadata_proxy_unittest.m.js
index 744a8f4..e5c9284 100644
--- a/ui/file_manager/file_manager/background/js/metadata_proxy_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/metadata_proxy_unittest.m.js
@@ -4,9 +4,12 @@
 
 // clang-format off
 import {assertEquals} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+
 import {MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+
 import {metadataProxy} from './metadata_proxy.m.js';
+
 // clang-format on
 
 export function testMetadataCaching(doneCallback) {
diff --git a/ui/file_manager/file_manager/background/js/mock_volume_manager.js b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
index f8d3197..1f253a6 100644
--- a/ui/file_manager/file_manager/background/js/mock_volume_manager.js
+++ b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
@@ -8,7 +8,7 @@
 // #import {VolumeInfoListImpl} from './volume_info_list_impl.m.js';
 // #import * as wrappedVolumeManagerFactory from './volume_manager_factory.m.js'; const {volumeManagerFactory} = wrappedVolumeManagerFactory;
 // #import {VolumeManagerImpl} from './volume_manager_impl.m.js';
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {MockEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
 // #import * as wrappedUtil from '../../common/js/util.m.js'; const {util} = wrappedUtil;
 // #import {str} from '../../common/js/util.m.js';
diff --git a/ui/file_manager/file_manager/background/js/mount_metrics_unittest.m.js b/ui/file_manager/file_manager/background/js/mount_metrics_unittest.m.js
index 605398027..f64a477 100644
--- a/ui/file_manager/file_manager/background/js/mount_metrics_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/mount_metrics_unittest.m.js
@@ -4,9 +4,9 @@
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {metrics} from '../../common/js/metrics.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 
 import {MountMetrics} from './mount_metrics.m.js';
 
diff --git a/ui/file_manager/file_manager/background/js/task_queue_unittest.m.js b/ui/file_manager/file_manager/background/js/task_queue_unittest.m.js
index 6a3e7ef9..4ddfa28 100644
--- a/ui/file_manager/file_manager/background/js/task_queue_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/task_queue_unittest.m.js
@@ -4,8 +4,8 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
 import {importer} from '../../common/js/importer_common.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 import {taskQueueInterfaces} from '../../externs/background/task_queue.m.js';
 
 import {taskQueue} from './task_queue.m.js';
diff --git a/ui/file_manager/file_manager/background/js/test_util_base.js b/ui/file_manager/file_manager/background/js/test_util_base.js
index 88166da..ade3c93 100644
--- a/ui/file_manager/file_manager/background/js/test_util_base.js
+++ b/ui/file_manager/file_manager/background/js/test_util_base.js
@@ -8,7 +8,7 @@
  */
 
 // clang-format off
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util} from '../../common/js/util.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
diff --git a/ui/file_manager/file_manager/background/js/trash_unittest.m.js b/ui/file_manager/file_manager/background/js/trash_unittest.m.js
index e072466..8672768 100644
--- a/ui/file_manager/file_manager/background/js/trash_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/trash_unittest.m.js
@@ -6,9 +6,9 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockDirectoryEntry, MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
 import {TrashDirs} from '../../common/js/trash.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 
 import {MockVolumeManager} from './mock_volume_manager.m.js';
 import {Trash} from './trash.m.js';
diff --git a/ui/file_manager/file_manager/background/js/volume_info_impl.js b/ui/file_manager/file_manager/background/js/volume_info_impl.js
index 6cf17b9..ceb1f20 100644
--- a/ui/file_manager/file_manager/background/js/volume_info_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_info_impl.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {FakeEntryImpl} from '../../common/js/files_app_entry_types.m.js';
 // #import {str} from '../../common/js/util.m.js';
 // #import {FilesAppEntry, FakeEntry} from '../../externs/files_app_entry_interfaces.m.js';
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
index 18a3e8c..9d04c08a 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -6,7 +6,7 @@
 // #import {EntryLocationImpl} from './entry_location_impl.m.js';
 // #import {VolumeInfoListImpl} from './volume_info_list_impl.m.js';
 // #import * as wrappedVolumeManagerUtil from './volume_manager_util.m.js'; const {volumeManagerUtil} = wrappedVolumeManagerUtil;
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import * as wrappedAsyncUtil from '../../common/js/async_util.m.js'; const {AsyncUtil} = wrappedAsyncUtil;
 // #import * as wrappedUtil from '../../common/js/util.m.js'; const {util} = wrappedUtil;
 // #import {VolumeInfo} from '../../externs/volume_info.m.js';
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js b/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
index 36b4dd7..b658bf4 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_unittest.m.js
@@ -5,10 +5,10 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {assertRejected, reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {assertRejected, reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 
 import {VolumeInfoImpl} from './volume_info_impl.m.js';
 import {volumeManagerFactory} from './volume_manager_factory.m.js';
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_util.js b/ui/file_manager/file_manager/background/js/volume_manager_util.js
index c55500cf..41e98247 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_util.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_util.js
@@ -9,7 +9,7 @@
 
 // clang-format off
 // #import {VolumeInfoImpl} from './volume_info_impl.m.js';
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import * as wrappedUtil from '../../common/js/util.m.js'; const {util} = wrappedUtil;
 // #import {str} from '../../common/js/util.m.js';
 // #import {VolumeInfo} from '../../externs/volume_info.m.js';
diff --git a/ui/file_manager/file_manager/common/js/BUILD.gn b/ui/file_manager/file_manager/common/js/BUILD.gn
index 838ea16..fb90201 100644
--- a/ui/file_manager/file_manager/common/js/BUILD.gn
+++ b/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -8,7 +8,6 @@
 import("//ui/webui/resources/js/cr.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 
-# TODO(tapted): This entire folder should move to //ui/file_manager/base.
 visibility = [
   "//chromeos/components/file_manager/resources/*",
   "//ui/file_manager/*",
@@ -28,10 +27,13 @@
 js_type_check("closure_compile_module") {
   uses_legacy_modules = true
   deps = [
+    ":app_util",
     ":async_util",
+    ":error_counter",
     ":file_operation_common",
     ":file_type",
     ":files_app_entry_types",
+    ":filtered_volume_manager",
     ":importer_common",
     ":lru_cache",
     ":metrics",
@@ -41,16 +43,19 @@
     ":storage_adapter",
     ":trash",
     ":util",
-    "//ui/file_manager/base/js:volume_manager_types",
+    ":volume_manager_types",
   ]
 }
 
 js_type_check("closure_compile_jsmodules") {
   deps = [
+    ":app_util.m",
     ":async_util.m",
+    ":error_counter.m",
     ":file_operation_common.m",
     ":file_type.m",
     ":files_app_entry_types.m",
+    ":filtered_volume_manager.m",
     ":importer_common.m",
     ":lru_cache.m",
     ":metrics.m",
@@ -60,6 +65,7 @@
     ":storage_adapter.m",
     ":trash.m",
     ":util.m",
+    ":volume_manager_types.m",
   ]
 
   closure_flags = strict_error_checking_closure_args + [
@@ -73,6 +79,8 @@
   uses_legacy_modules = true
   testonly = true
   deps = [
+    ":mock_chrome",
+    ":test_error_reporting",
     ":test_importer_common",
     ":unittest_util",
   ]
@@ -81,6 +89,8 @@
 js_type_check("test_support_modules_type_check") {
   testonly = true
   deps = [
+    ":mock_chrome.m",
+    ":test_error_reporting.m",
     ":test_importer_common.m",
     ":unittest_util.m",
   ]
@@ -90,6 +100,31 @@
       [ "browser_resolver_prefix_replacements=\"chrome://test/=./\"" ]
 }
 
+js_library("app_util") {
+  deps = [
+    ":volume_manager_types",
+    "//ui/file_manager/file_manager/externs:volume_manager",
+  ]
+  externs_list = [
+    "//ui/file_manager/file_manager/externs/app_window_common.js",
+    "//ui/file_manager/file_manager/externs/background/background_base.js",
+  ]
+}
+
+js_library("app_util.m") {
+  sources =
+      [ "$root_gen_dir/ui/file_manager/file_manager/common/js/app_util.m.js" ]
+  deps = [
+    "//ui/file_manager/file_manager/externs:file_manager_private",
+    "//ui/file_manager/file_manager/externs:volume_manager.m",
+    "//ui/file_manager/file_manager/externs/background:background_base.m",
+  ]
+  externs_list =
+      [ "//ui/file_manager/file_manager/externs/app_window_common.js" ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("async_util") {
 }
 
@@ -100,6 +135,17 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("error_counter") {
+}
+
+js_library("error_counter.m") {
+  sources = [
+    "$root_gen_dir/ui/file_manager/file_manager/common/js/error_counter.m.js",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("files_app_entry_types") {
   deps = [ "//ui/file_manager/file_manager/externs:file_manager_private" ]
   externs_list = [
@@ -113,7 +159,7 @@
     ":files_app_entry_types.m",
     ":mock_entry.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -122,7 +168,7 @@
 js_library("files_app_entry_types.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/files_app_entry_types.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
   ]
 
@@ -132,7 +178,7 @@
 js_library("file_type") {
   deps = [
     ":files_app_entry_types",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -141,7 +187,7 @@
       [ "$root_gen_dir/ui/file_manager/file_manager/common/js/file_type.m.js" ]
   deps = [
     ":files_app_entry_types.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -154,7 +200,7 @@
     ":file_type.m",
     ":mock_entry.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 }
 
@@ -174,6 +220,38 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("filtered_volume_manager") {
+  deps = [
+    "//ui/file_manager/file_manager/common/js:async_util",
+    "//ui/file_manager/file_manager/common/js:files_app_entry_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
+    "//ui/file_manager/file_manager/externs:file_manager_private",
+    "//ui/file_manager/file_manager/externs:volume_manager",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js/cr/ui:array_data_model",
+  ]
+  externs_list = [ "//ui/file_manager/file_manager/externs/background/volume_manager_factory.js" ]
+}
+
+js_library("filtered_volume_manager.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/filtered_volume_manager.m.js" ]
+  deps = [
+    "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/externs:entry_location.m",
+    "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
+    "//ui/file_manager/file_manager/externs:volume_info.m",
+    "//ui/file_manager/file_manager/externs:volume_info_list.m",
+    "//ui/file_manager/file_manager/externs:volume_manager.m",
+    "//ui/webui/resources/js:assert.m",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js/cr:event_target.m",
+    "//ui/webui/resources/js/cr/ui:array_data_model.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 # These importer files actually belong here. Nothing outside the Files app uses
 # them, so restrict visibility. TODO(tapted): Simplify visibility when
 # everything else moves to //ui/file_manager/base.
@@ -182,7 +260,7 @@
   visibility = [ "//ui/file_manager/file_manager/*" ]
   deps = [
     ":file_type",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
   ]
 }
@@ -193,7 +271,7 @@
   ]
   deps = [
     ":file_type.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
@@ -207,8 +285,8 @@
   deps = [
     ":importer_common",
     ":unittest_util",
-    "//ui/file_manager/base/js:mock_chrome",
-    "//ui/file_manager/base/js:test_error_reporting",
+    "//ui/file_manager/file_manager/common/js:mock_chrome",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
   visibility = []
   visibility = [ "//ui/file_manager/file_manager/*" ]
@@ -230,10 +308,10 @@
     ":mock_entry.m",
     ":test_importer_common.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
   ]
 }
@@ -255,6 +333,15 @@
   ]
 }
 
+js_library("mediasession_types") {
+}
+
+js_library("mediasession_types.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/mediasession_types.m.js" ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("metrics") {
   visibility = []
   visibility = [ "//ui/file_manager/file_manager/*" ]
@@ -288,6 +375,19 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("mock_chrome") {
+  testonly = true
+}
+
+js_library("mock_chrome.m") {
+  testonly = true
+  sources = [
+    "$root_gen_dir/ui/file_manager/file_manager/common/js/mock_chrome.m.js",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("mock_entry") {
   deps = [
     ":util",
@@ -323,10 +423,26 @@
   extra_deps = [ ":modulize" ]
 }
 
+js_library("test_error_reporting") {
+  testonly = true
+  deps = [
+    # Note we allow targets depending on test_error_reporting to access
+    # webui_resource_test transitively.
+    "//ui/webui/resources/js:webui_resource_test",
+  ]
+}
+
+js_library("test_error_reporting.m") {
+  testonly = true
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/test_error_reporting.m.js" ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_library("trash") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
   externs_list = [
     "//ui/file_manager/file_manager/externs/files_app_entry_interfaces.js",
@@ -341,7 +457,7 @@
   deps = [
     ":files_app_entry_types.m",
     ":util.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
@@ -376,8 +492,8 @@
 
     # TODO(tapted): Remove these base util dependencies, which exist temporarily
     # to allow targets to depend only on util, if they depend on one of these.
-    "//ui/file_manager/base/js:app_util",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:app_util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/webui/resources/js:load_time_data",
     "//ui/webui/resources/js:util",
     "//ui/webui/resources/js/cr:event_target",
@@ -398,8 +514,8 @@
 
   deps = [
     ":files_app_entry_types.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:file_manager_private",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
@@ -425,11 +541,33 @@
     ":mock_entry.m",
     ":util.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 }
 
+js_library("volume_manager_types") {
+  deps = [
+    "//ui/file_manager/file_manager/externs:file_manager_private",
+    "//ui/webui/resources/js:assert",
+  ]
+}
+
+js_unittest("volume_manager_types_unittest.m") {
+  deps = [ ":volume_manager_types.m" ]
+}
+
+js_library("volume_manager_types.m") {
+  sources = [ "$root_gen_dir/ui/file_manager/file_manager/common/js/volume_manager_types.m.js" ]
+
+  deps = [
+    "//ui/file_manager/file_manager/externs:file_manager_private",
+    "//ui/webui/resources/js:assert.m",
+  ]
+
+  extra_deps = [ ":modulize" ]
+}
+
 js_test_gen_html("js_test_gen_html_modules") {
   js_module = true
   deps = [
@@ -438,6 +576,7 @@
     ":importer_common_unittest.m",
     ":lru_cache_unittest.m",
     ":util_unittest.m",
+    ":volume_manager_types_unittest.m",
   ]
 
   closure_flags =
@@ -451,21 +590,28 @@
 
 js_modulizer("modulize") {
   input_files = [
+    "app_util.js",
     "async_util.js",
+    "error_counter.js",
     "file_operation_common.js",
     "file_type.js",
     "files_app_entry_types.js",
+    "filtered_volume_manager.js",
     "importer_common.js",
     "lru_cache.js",
+    "mediasession_types.js",
     "metrics.js",
     "metrics_base.js",
+    "mock_chrome.js",
     "mock_entry.js",
     "progress_center_common.js",
     "storage_adapter.js",
+    "test_error_reporting.js",
     "test_importer_common.js",
     "trash.js",
     "unittest_util.js",
     "util.js",
+    "volume_manager_types.js",
   ]
 
   namespace_rewrites = cr_namespace_rewrites
diff --git a/ui/file_manager/base/js/app_util.js b/ui/file_manager/file_manager/common/js/app_util.js
similarity index 96%
rename from ui/file_manager/base/js/app_util.js
rename to ui/file_manager/file_manager/common/js/app_util.js
index 7a13c705..b124d78 100644
--- a/ui/file_manager/base/js/app_util.js
+++ b/ui/file_manager/file_manager/common/js/app_util.js
@@ -9,8 +9,8 @@
  */
 
 // clang-format off
-// #import {BackgroundBase} from '../../file_manager/externs/background/background_base.m.js';
-// #import {VolumeManager} from '../../file_manager/externs/volume_manager.m.js';
+// #import {BackgroundBase} from '../../externs/background/background_base.m.js';
+// #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // clang-format on
 
 const appUtil = {};
diff --git a/ui/file_manager/base/js/error_counter.js b/ui/file_manager/file_manager/common/js/error_counter.js
similarity index 100%
rename from ui/file_manager/base/js/error_counter.js
rename to ui/file_manager/file_manager/common/js/error_counter.js
diff --git a/ui/file_manager/file_manager/common/js/file_operation_common.js b/ui/file_manager/file_manager/common/js/file_operation_common.js
index 4c7b8e3..58dbe956 100644
--- a/ui/file_manager/file_manager/common/js/file_operation_common.js
+++ b/ui/file_manager/file_manager/common/js/file_operation_common.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {util} from '../../common/js/util.m.js';
+// #import {util} from './util.m.js';
 // #import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.m.js'
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/common/js/file_type.js b/ui/file_manager/file_manager/common/js/file_type.js
index 98b5b76..f47cb39 100644
--- a/ui/file_manager/file_manager/common/js/file_type.js
+++ b/ui/file_manager/file_manager/common/js/file_type.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.m.js';
 // #import {VolumeEntry} from './files_app_entry_types.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
diff --git a/ui/file_manager/file_manager/common/js/file_type_unittest.m.js b/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
index 668e4c1..77dfa0fe6 100644
--- a/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/file_type_unittest.m.js
@@ -4,7 +4,8 @@
 
 import {FileType} from './file_type.m.js';
 import {MockFileSystem} from './mock_entry.m.js';
-import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js';
+import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js';
+
 const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 import {assertEquals} from 'chrome://test/chai_assert.js';
 
diff --git a/ui/file_manager/file_manager/common/js/files_app_entry_types.js b/ui/file_manager/file_manager/common/js/files_app_entry_types.js
index 9ecb349b..4488ce87 100644
--- a/ui/file_manager/file_manager/common/js/files_app_entry_types.js
+++ b/ui/file_manager/file_manager/common/js/files_app_entry_types.js
@@ -22,7 +22,7 @@
  */
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {FilesAppEntry, FilesAppDirEntry, FakeEntry} from '../../externs/files_app_entry_interfaces.m.js';
 // #import {VolumeInfo} from '../../externs/volume_info.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.m.js b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.m.js
index 94ad8c1..d4ab2c9c 100644
--- a/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.m.js
@@ -6,11 +6,11 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js';
+import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js';
 const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 
 import {MockFileSystem} from './mock_entry.m.js';
-import {reportPromise, waitUntil} from '../../../base/js/test_error_reporting.m.js';
+import {reportPromise, waitUntil} from './test_error_reporting.m.js';
 import {VolumeEntry, EntryList, StaticReader, CombinedReaders, FakeEntryImpl} from './files_app_entry_types.m.js';
 import {VolumeInfo} from '../../externs/volume_info.m.js';
 // clang-format on
diff --git a/ui/file_manager/base/js/filtered_volume_manager.js b/ui/file_manager/file_manager/common/js/filtered_volume_manager.js
similarity index 96%
rename from ui/file_manager/base/js/filtered_volume_manager.js
rename to ui/file_manager/file_manager/common/js/filtered_volume_manager.js
index 0380c92..e1644d588 100644
--- a/ui/file_manager/base/js/filtered_volume_manager.js
+++ b/ui/file_manager/file_manager/common/js/filtered_volume_manager.js
@@ -4,11 +4,11 @@
 
 // clang-format off
 // #import {assert} from 'chrome://resources/js/assert.m.js';
-// #import {VolumeInfo} from '../../file_manager/externs/volume_info.m.js';
-// #import {VolumeInfoList} from '../../file_manager/externs/volume_info_list.m.js';
-// #import {VolumeManager, ExternallyUnmountedEvent} from '../../file_manager/externs/volume_manager.m.js';
-// #import {FilesAppEntry} from '../../file_manager/externs/files_app_entry_interfaces.m.js';
-// #import {EntryLocation} from '../../file_manager/externs/entry_location.m.js';
+// #import {VolumeInfo} from '../../externs/volume_info.m.js';
+// #import {VolumeInfoList} from '../../externs/volume_info_list.m.js';
+// #import {VolumeManager, ExternallyUnmountedEvent} from '../../externs/volume_manager.m.js';
+// #import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.m.js';
+// #import {EntryLocation} from '../../externs/entry_location.m.js';
 // #import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js'; const {VolumeManagerCommon, AllowedPaths} = wrappedVolumeManagerCommon;
 // #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
 // #import {ArrayDataModel} from 'chrome://resources/js/cr/ui/array_data_model.m.js';
diff --git a/ui/file_manager/file_manager/common/js/importer_common.js b/ui/file_manager/file_manager/common/js/importer_common.js
index 03ada23..1520241f 100644
--- a/ui/file_manager/file_manager/common/js/importer_common.js
+++ b/ui/file_manager/file_manager/common/js/importer_common.js
@@ -12,7 +12,7 @@
 // #import {VolumeInfo} from '../../externs/volume_info.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {FileType} from './file_type.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from './volume_manager_types.m.js';
 // clang-format on
 
 // Namespace
diff --git a/ui/file_manager/file_manager/common/js/importer_common_unittest.m.js b/ui/file_manager/file_manager/common/js/importer_common_unittest.m.js
index 692f6fd0..e29a6b62 100644
--- a/ui/file_manager/file_manager/common/js/importer_common_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/importer_common_unittest.m.js
@@ -4,15 +4,15 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {MockChromeStorageAPI, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
 import {VolumeInfo} from '../../externs/volume_info.m.js';
 
 import {importer} from './importer_common.m.js';
+import {MockChromeStorageAPI, MockCommandLinePrivate} from './mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileEntry} from './mock_entry.m.js';
+import {reportPromise} from './test_error_reporting.m.js';
 import {importerTest} from './test_importer_common.m.js';
+import {VolumeManagerCommon} from './volume_manager_types.m.js';
 
 /** @type {!MockVolumeManager} */
 let volumeManager;
diff --git a/ui/file_manager/base/js/mediasession_types.js b/ui/file_manager/file_manager/common/js/mediasession_types.js
similarity index 100%
rename from ui/file_manager/base/js/mediasession_types.js
rename to ui/file_manager/file_manager/common/js/mediasession_types.js
diff --git a/ui/file_manager/base/js/mock_chrome.js b/ui/file_manager/file_manager/common/js/mock_chrome.js
similarity index 100%
rename from ui/file_manager/base/js/mock_chrome.js
rename to ui/file_manager/file_manager/common/js/mock_chrome.js
diff --git a/ui/file_manager/base/js/test_error_reporting.js b/ui/file_manager/file_manager/common/js/test_error_reporting.js
similarity index 100%
rename from ui/file_manager/base/js/test_error_reporting.js
rename to ui/file_manager/file_manager/common/js/test_error_reporting.js
diff --git a/ui/file_manager/file_manager/common/js/trash.js b/ui/file_manager/file_manager/common/js/trash.js
index 870e4a5e..d1e0ba0 100644
--- a/ui/file_manager/file_manager/common/js/trash.js
+++ b/ui/file_manager/file_manager/common/js/trash.js
@@ -25,7 +25,7 @@
 // #import {assert} from 'chrome://resources/js/assert.m.js';
 // #import {util} from './util.m.js';
 // #import {FakeEntryImpl, CombinedReaders} from './files_app_entry_types.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from './volume_manager_types.m.js';
 // clang-format on
 
 /**
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 5f9a245c..fb1fbfd 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -13,7 +13,7 @@
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // #import {queryRequiredElement} from 'chrome://resources/js/util.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
-// #import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {decorate} from 'chrome://resources/js/cr/ui.m.js';
 // #import {FilesAppEntry, FakeEntry} from '../../externs/files_app_entry_interfaces.m.js';
 // #import {EntryList} from './files_app_entry_types.m.js';
@@ -1204,7 +1204,7 @@
     if (entry.fullPath == '/PvmDefault') {
       return str('PLUGIN_VM_DIRECTORY_LABEL');
     }
-    if (util.isFilesCameraFolderEnabled() && entry.fullPath == '/Camera') {
+    if (entry.fullPath == '/Camera') {
       return str('CAMERA_DIRECTORY_LABEL');
     }
   }
@@ -1260,7 +1260,7 @@
       return true;
     }
 
-    if (fullPath === '/Camera' && util.isFilesCameraFolderEnabled()) {
+    if (fullPath === '/Camera') {
       return true;
     }
 
@@ -1445,14 +1445,6 @@
 };
 
 /**
- * Returns true when FilesCameraFolder is enabled.
- * @return {boolean}
- */
-util.isFilesCameraFolderEnabled = () => {
-  return loadTimeData.getBoolean('FILES_CAMERA_FOLDER_ENABLED');
-};
-
-/**
  * Returns true when FilesNG is enabled.
  * @return {boolean}
  */
diff --git a/ui/file_manager/file_manager/common/js/util_unittest.m.js b/ui/file_manager/file_manager/common/js/util_unittest.m.js
index c879dd0..8671372 100644
--- a/ui/file_manager/file_manager/common/js/util_unittest.m.js
+++ b/ui/file_manager/file_manager/common/js/util_unittest.m.js
@@ -6,7 +6,7 @@
 import {MockFileSystem} from './mock_entry.m.js';
 import * as wrappedUtil from './util.m.js';
 const {util} = wrappedUtil;
-import * as wrappedVolumeManagerCommon from '../../../base/js/volume_manager_types.m.js';
+import * as wrappedVolumeManagerCommon from './volume_manager_types.m.js';
 const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
 import {assertEquals, assertTrue, assertFalse} from 'chrome://test/chai_assert.js';
diff --git a/ui/file_manager/base/js/volume_manager_types.js b/ui/file_manager/file_manager/common/js/volume_manager_types.js
similarity index 100%
rename from ui/file_manager/base/js/volume_manager_types.js
rename to ui/file_manager/file_manager/common/js/volume_manager_types.js
diff --git a/ui/file_manager/base/js/volume_manager_types_unittest.m.js b/ui/file_manager/file_manager/common/js/volume_manager_types_unittest.m.js
similarity index 100%
rename from ui/file_manager/base/js/volume_manager_types_unittest.m.js
rename to ui/file_manager/file_manager/common/js/volume_manager_types_unittest.m.js
diff --git a/ui/file_manager/file_manager/externs/BUILD.gn b/ui/file_manager/file_manager/externs/BUILD.gn
index 868cb51..010dd726 100644
--- a/ui/file_manager/file_manager/externs/BUILD.gn
+++ b/ui/file_manager/file_manager/externs/BUILD.gn
@@ -84,7 +84,7 @@
 
   deps = [
     ":volume_info.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 
   extra_deps = [ ":modulize" ]
@@ -104,7 +104,7 @@
 js_library("files_app_entry_interfaces.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/externs/files_app_entry_interfaces.m.js" ]
 
-  deps = [ "//ui/file_manager/base/js:volume_manager_types.m" ]
+  deps = [ "//ui/file_manager/file_manager/common/js:volume_manager_types.m" ]
 
   extra_deps = [ ":modulize" ]
 }
@@ -146,7 +146,7 @@
     ":files_app_entry_interfaces.m",
     ":volume_info.m",
     ":volume_info_list.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 
   extra_deps = [ ":modulize" ]
@@ -158,7 +158,7 @@
 
   deps = [
     ":files_app_entry_interfaces.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 
   extra_deps = [ ":modulize" ]
diff --git a/ui/file_manager/file_manager/externs/app_window_common.js b/ui/file_manager/file_manager/externs/app_window_common.js
index 4bdea79..6f306866 100644
--- a/ui/file_manager/file_manager/externs/app_window_common.js
+++ b/ui/file_manager/file_manager/externs/app_window_common.js
@@ -4,7 +4,7 @@
 
 /**
  * This definition is required by
- * ui/file_manager/base/js/app_util.js.
+ * ui/file_manager/file_manager/common/js/app_util.js.
  * @type {string}
  */
 Window.prototype.appID;
diff --git a/ui/file_manager/file_manager/externs/entry_location.js b/ui/file_manager/file_manager/externs/entry_location.js
index 152da70b..d98b34b 100644
--- a/ui/file_manager/file_manager/externs/entry_location.js
+++ b/ui/file_manager/file_manager/externs/entry_location.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {VolumeInfo} from './volume_info.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/externs/files_app_entry_interfaces.js b/ui/file_manager/file_manager/externs/files_app_entry_interfaces.js
index c22638b..b906b6b 100644
--- a/ui/file_manager/file_manager/externs/files_app_entry_interfaces.js
+++ b/ui/file_manager/file_manager/externs/files_app_entry_interfaces.js
@@ -7,7 +7,7 @@
  */
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // clang-format on
 
 /**
diff --git a/ui/file_manager/file_manager/externs/volume_info.js b/ui/file_manager/file_manager/externs/volume_info.js
index e346aae..a7c29747 100644
--- a/ui/file_manager/file_manager/externs/volume_info.js
+++ b/ui/file_manager/file_manager/externs/volume_info.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import * as wrappedVolumeManagerCommon from '../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {FilesAppEntry, FakeEntry} from './files_app_entry_interfaces.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/externs/volume_manager.js b/ui/file_manager/file_manager/externs/volume_manager.js
index 2e2f13a..3be5964d 100644
--- a/ui/file_manager/file_manager/externs/volume_manager.js
+++ b/ui/file_manager/file_manager/externs/volume_manager.js
@@ -7,7 +7,7 @@
 // #import {VolumeInfo} from './volume_info.m.js';
 // #import {VolumeInfoList} from './volume_info_list.m.js';
 // #import {FilesAppEntry, FilesAppDirEntry} from './files_app_entry_interfaces.m.js';
-// #import * as wrappedVolumeManagerCommon from '../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // clang-format on
 
 /**
diff --git a/ui/file_manager/file_manager/foreground/css/file_types.css b/ui/file_manager/file_manager/foreground/css/file_types.css
index 36ee2ae..33efdd4 100644
--- a/ui/file_manager/file_manager/foreground/css/file_types.css
+++ b/ui/file_manager/file_manager/foreground/css/file_types.css
@@ -276,16 +276,12 @@
   background-image: none;
 }
 
-[file-type-icon='camera-folder'] {
-  -webkit-mask-image: url(../images/filetype/filetype_folder.svg);
+body.files-ng [file-type-icon='camera-folder'] {
+  -webkit-mask-image: url(../images/volumes/camera.svg);
   background-color: currentColor;
   background-image: none;
 }
 
-body.camera-folder-enabled [file-type-icon='camera-folder'] {
-  -webkit-mask-image: url(../images/volumes/camera.svg);
-}
-
 .tree-row > .file-row > [volume-type-icon='drive'] {
   -webkit-mask-image: url(../images/volumes/drive.svg);
 }
diff --git a/ui/file_manager/file_manager/foreground/elements/BUILD.gn b/ui/file_manager/file_manager/foreground/elements/BUILD.gn
index 86a35c0..ba36c51a 100644
--- a/ui/file_manager/file_manager/foreground/elements/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/elements/BUILD.gn
@@ -104,7 +104,7 @@
   auto_imports = [
     "ui/file_manager/file_manager/common/js/util.html|util",
     "ui/file_manager/file_manager/common/js/files_app_entry_types.html|EntryList,VolumeEntry",
-    "ui/file_manager/base/js/volume_manager_types.html|VolumeManagerCommon",
+    "ui/file_manager/file_manager/common/js/volume_manager_types.html|VolumeManagerCommon",
     "ui/file_manager/file_manager/externs/volume_info.html|VolumeInfo",
   ]
 }
@@ -115,9 +115,9 @@
   deps = [
     "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
     "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
@@ -241,7 +241,7 @@
   deps = [
     ":files_password_dialog.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/webui/resources/js:assert.m",
   ]
 }
@@ -404,7 +404,7 @@
   deps = [
     ":files_tooltip.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
diff --git a/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html b/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
index b415f12a..44b5924 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_format_dialog.html
@@ -17,7 +17,7 @@
 
 <!-- <link rel="import" href="../../common/js/util.html"> -->
 <!-- <link rel="import" href="../../common/js/files_app_entry_types.html"> -->
-<!-- <link rel="import" href="../../../base/js/volume_manager_types.html"> -->
+<!-- <link rel="import" href="../../common/js/volume_manager_types.html"> -->
 <!-- <link rel="import" href="../../externs/volume_info.html"> -->
 
 <dom-module id="files-format-dialog">
diff --git a/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.m.js b/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.m.js
index 668f641e..584087be 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_password_dialog_unittest.m.js
@@ -9,7 +9,7 @@
 
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {assertEquals, assertFalse, assertNotReached} from 'chrome://test/chai_assert.js';
-import {waitUntil} from '../../../base/js/test_error_reporting.m.js';
+import {waitUntil} from '../../common/js/test_error_reporting.m.js';
 import {FilesPasswordDialog} from './files_password_dialog.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/foreground/elements/files_tooltip_unittest.m.js b/ui/file_manager/file_manager/foreground/elements/files_tooltip_unittest.m.js
index 3cbc0653..a09c5ed 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_tooltip_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_tooltip_unittest.m.js
@@ -5,7 +5,7 @@
 // clang-format off
 import {assertEquals, assertFalse, assertNotEquals, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 
 import {FilesTooltip} from './files_tooltip.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index 71e28e1..5a28f6f 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -256,9 +256,9 @@
     ":folder_shortcuts_data_model.m",
     "metadata:metadata_model.m",
     "ui:action_model_ui.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:drive_sync_handler.m",
     "//ui/webui/resources/js:assert.m",
@@ -314,13 +314,13 @@
     "ui:files_alert_dialog.m",
     "ui:list_container.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_drive_sync_handler.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js/cr:event_target.m",
   ]
@@ -438,7 +438,7 @@
     ":directory_model.m",
     "ui:file_manager_ui.m",
     "ui:list_container.m",
-    "//ui/file_manager/base/js:app_util.m",
+    "//ui/file_manager/file_manager/common/js:app_util.m",
     "//ui/file_manager/file_manager/common/js:util.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -450,7 +450,7 @@
   deps = [
     ":directory_model",
     "ui:file_manager_ui",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -459,8 +459,8 @@
   deps = [
     ":directory_model.m",
     "ui:file_manager_ui.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
 
@@ -508,9 +508,9 @@
     ":file_manager_commands.m",
     ":navigation_list_model.m",
     "ui:directory_tree.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs/background:crostini.m",
     "//ui/file_manager/file_manager/foreground/elements:files_message.m",
     "//ui/file_manager/file_manager/foreground/elements:files_toast.m",
@@ -546,9 +546,9 @@
     ":naming_controller.m",
     "metadata:metadata_model.m",
     "ui:dialog_footer.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:util.m",
@@ -574,10 +574,10 @@
     ":constants",
     ":file_list_model",
     "metadata:metadata_model",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:async_util",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js/cr/ui:array_data_model",
@@ -590,10 +590,10 @@
     ":constants.m",
     ":file_list_model.m",
     "metadata:metadata_model.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
@@ -608,7 +608,7 @@
   deps = [
     ":directory_contents.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
@@ -636,10 +636,10 @@
     ":file_watcher.m",
     "metadata:metadata_model.m",
     "ui:file_list_selection_model.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entries_changed_event.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
@@ -665,8 +665,8 @@
 js_library("navigation_uma.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/navigation_uma.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
 
@@ -844,7 +844,7 @@
     "ui:commandbutton",
     "ui:directory_tree",
     "ui:file_manager_ui",
-    "//ui/file_manager/base/js:filtered_volume_manager",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager",
     "//ui/file_manager/file_manager/common/js:storage_adapter",
     "//ui/webui/resources/js/cr/ui:list_selection_model",
   ]
@@ -906,13 +906,13 @@
     "ui:file_manager_ui.m",
     "ui:file_metadata_formatter.m",
     "ui:file_table.m",
-    "//ui/file_manager/base/js:filtered_volume_manager.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
     "//ui/file_manager/file_manager/common/js:storage_adapter.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:background_window.m",
     "//ui/file_manager/file_manager/externs:command_handler_deps.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
@@ -980,7 +980,6 @@
     ":webui_command_extender.m",
     "ui:directory_tree.m",
     "ui:files_confirm_dialog.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_operation_common.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
@@ -988,6 +987,7 @@
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
     "//ui/file_manager/file_manager/common/js:trash.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:command_handler_deps.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
@@ -1007,10 +1007,10 @@
     ":file_manager_commands.m",
     ":file_tasks.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 }
@@ -1021,9 +1021,9 @@
     ":directory_model",
     "metadata:metadata_model",
     "ui:list_container",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:file_type",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
   ]
@@ -1036,9 +1036,9 @@
     ":directory_model.m",
     "metadata:metadata_model.m",
     "ui:list_container.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:file_operation_manager.m",
     "//ui/webui/resources/js:assert.m",
@@ -1083,12 +1083,12 @@
     "ui:files_confirm_dialog.m",
     "ui:files_menu.m",
     "ui:multi_menu_button.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:crostini.m",
@@ -1113,13 +1113,13 @@
     "metadata:metadata_model.m",
     "ui:file_manager_ui.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_crostini.m",
     "//ui/file_manager/file_manager/background/js:mock_progress_center.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:progress_center.m",
@@ -1158,10 +1158,10 @@
     "ui:directory_tree.m",
     "ui:drag_selector.m",
     "ui:list_container.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:progress_center_common.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
@@ -1194,10 +1194,10 @@
     "ui:file_table.m",
     "ui:list_container.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:file_operation_manager.m",
     "//ui/file_manager/file_manager/externs/background:import_history.m",
@@ -1232,9 +1232,9 @@
     ":directory_model.m",
     ":file_type_filters_controller.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/webui/resources/js:load_time_data.m",
     "//ui/webui/resources/js/cr:event_target.m",
@@ -1243,9 +1243,9 @@
 
 js_library("file_watcher") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:async_util",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/webui/resources/js:assert",
   ]
 }
@@ -1265,11 +1265,11 @@
 
 js_library("folder_shortcuts_data_model") {
   deps = [
-    "//ui/file_manager/base/js:filtered_volume_manager",
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:async_util",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/webui/resources/js/cr:event_target",
   ]
 }
@@ -1277,11 +1277,11 @@
 js_library("folder_shortcuts_data_model.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:filtered_volume_manager.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:async_util.m",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js/cr:event_target.m",
   ]
 
@@ -1306,8 +1306,8 @@
     "ui:gear_menu.m",
     "ui:multi_menu_button.m",
     "ui:providers_menu.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:directory_change_event.m",
   ]
 
@@ -1316,7 +1316,7 @@
 
 js_library("holding_space_util") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:load_time_data",
   ]
@@ -1325,8 +1325,8 @@
 js_library("holding_space_util.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/holding_space_util.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
 
@@ -1360,10 +1360,10 @@
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/import_controller.m.js" ]
   deps = [
     ":file_selection.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:importer_common.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:command_handler_deps.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
@@ -1382,12 +1382,12 @@
   deps = [
     ":import_controller.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_media_scanner.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:media_import_handler.m",
@@ -1417,7 +1417,7 @@
 js_library("launch_param") {
   deps = [
     ":dialog_type",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -1425,7 +1425,7 @@
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/launch_param.m.js" ]
   deps = [
     ":dialog_type.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
   ]
 
   extra_deps = [ ":modulize" ]
@@ -1437,7 +1437,7 @@
     ":file_list_model",
     ":thumbnail_loader",
     "metadata:thumbnail_model",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
@@ -1448,8 +1448,8 @@
     ":file_list_model.m",
     ":thumbnail_loader.m",
     "metadata:thumbnail_model.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:lru_cache.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js/cr:event_target.m",
@@ -1467,9 +1467,9 @@
     "metadata:metadata_model.m",
     "metadata:thumbnail_model.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js/cr:event_target.m",
@@ -1520,9 +1520,9 @@
     "ui:file_manager_ui.m",
     "ui:file_tap_handler.m",
     "ui:list_container.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:directory_change_event.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
@@ -1635,10 +1635,10 @@
     ":directory_model.m",
     ":folder_shortcuts_data_model.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
     "//ui/file_manager/file_manager/common/js:trash.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
@@ -1658,27 +1658,27 @@
     ":mock_folder_shortcut_data_model.m",
     ":navigation_list_model.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
     "//ui/file_manager/file_manager/background/js:volume_info_impl.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
   ]
 }
 
 js_library("path_component") {
-  deps = [ "//ui/file_manager/base/js:volume_manager_types" ]
+  deps = [ "//ui/file_manager/file_manager/common/js:volume_manager_types" ]
 }
 
 js_library("path_component.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/path_component.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
   ]
 
@@ -1692,7 +1692,7 @@
 js_library("providers_model.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/providers_model.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -1704,12 +1704,12 @@
   deps = [
     ":providers_model.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
     "//ui/file_manager/file_manager/background/js:volume_info_impl.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
 }
@@ -1747,9 +1747,9 @@
     "ui:files_confirm_dialog.m",
     "ui:list_container.m",
     "ui:multi_menu_button.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:command_handler_deps.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/foreground/elements:files_quick_view.m",
@@ -1791,9 +1791,9 @@
   deps = [
     ":dialog_type.m",
     ":file_tasks.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -1841,8 +1841,8 @@
     "ui:file_manager_ui.m",
     "ui:location_line.m",
     "ui:search_box.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:entry_location.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
@@ -1903,7 +1903,7 @@
   deps = [
     ":spinner_controller.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/webui/resources/js:assert.m",
   ]
 }
@@ -1960,13 +1960,13 @@
     "metadata:mock_metadata.m",
     "ui:file_manager_ui.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_crostini.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/externs/background:progress_center.m",
     "//ui/webui/resources/js:assert.m",
@@ -2017,8 +2017,8 @@
   deps = [
     ":thumbnail_loader.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/image_loader:image_loader_client.m",
     "//ui/file_manager/image_loader:load_image_request.m",
   ]
@@ -2043,8 +2043,8 @@
     "ui:file_list_selection_model.m",
     "ui:list_container.m",
     "ui:location_line.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:util.m",
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index bb202ec..20ced56 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -8,7 +8,7 @@
 // #import {DriveSyncHandler} from '../../externs/background/drive_sync_handler.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {MetadataModel} from './metadata/metadata_model.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util, str, strf} from '../../common/js/util.m.js';
 // #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.m.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.m.js
index 10cfd8f..13e7dff 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.m.js
@@ -5,13 +5,15 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+
 import {MockDriveSyncHandler} from '../../background/js/mock_drive_sync_handler.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
 import {metrics} from '../../common/js/metrics.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileEntry} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
+
 import {ActionsModel} from './actions_model.m.js';
 import {FolderShortcutsDataModel} from './folder_shortcuts_data_model.m.js';
 import {MockMetadataModel} from './metadata/mock_metadata.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/app_state_controller.js b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
index b7ecf687..090ec4c 100644
--- a/ui/file_manager/file_manager/foreground/js/app_state_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/app_state_controller.js
@@ -6,7 +6,7 @@
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {DialogType} from './dialog_type.m.js';
 // #import {util} from '../../common/js/util.m.js';
-// #import {appUtil} from '../../../base/js/app_util.m.js';
+// #import {appUtil} from '../../common/js/app_util.m.js';
 // #import {ListContainer} from './ui/list_container.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js b/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
index ea6bc5ef..2525e22 100644
--- a/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/column_visibility_controller.js
@@ -6,7 +6,7 @@
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {FileManagerUI} from './ui/file_manager_ui.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {importer} from '../../common/js/importer_common.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_controller.js b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
index 142cce7..0b4486a 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini_controller.js
@@ -9,7 +9,7 @@
 // #import {FilesMessage} from '../elements/files_message.m.js';
 // #import {Crostini} from '../../externs/background/crostini.m.js';
 // #import {CommandHandler} from './file_manager_commands.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {FakeEntryImpl} from '../../common/js/files_app_entry_types.m.js';
 // #import {str, strf} from '../../common/js/util.m.js';
 // #import {NavigationModelFakeItem, NavigationModelItemType} from './navigation_list_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
index e91922c..f748d86 100644
--- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
@@ -11,7 +11,7 @@
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {DialogFooter} from './ui/dialog_footer.m.js';
 // #import {util, str} from '../../common/js/util.m.js';
-// #import {VolumeManagerCommon, AllowedPaths} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon, AllowedPaths} from '../../common/js/volume_manager_types.m.js';
 // #import {DialogType} from './dialog_type.m.js';
 // #import {FileSelectionHandler} from './file_selection.m.js';
 // #import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 33ac3463..df74dd1 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -9,7 +9,7 @@
 // #import {FileListModel} from './file_list_model.m.js';
 // #import {AsyncUtil} from '../../common/js/async_util.m.js';
 // #import {constants} from './constants.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
 // #import {util} from '../../common/js/util.m.js';
 // #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js b/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
index 5c6c35b..647caffd 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents_unittest.m.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 import {assertEquals, assertFalse} from 'chrome://test/chai_assert.js';
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {EntryLocation} from '../../externs/entry_location.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
 import {FileFilter} from './directory_contents.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index be4dc61..9dbe6ee 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -17,7 +17,7 @@
 // #import {FileListContext, DirectoryContents, DirectoryContentScanner, RecentContentScanner, CrostiniMounter, DriveSearchContentScanner, LocalSearchContentScanner, MediaViewContentScanner, DriveMetadataSearchContentScanner, ContentScanner, FileFilter} from './directory_contents.m.js';
 // #import {constants} from './constants.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util} from '../../common/js/util.m.js';
 // #import {AsyncUtil} from '../../common/js/async_util.m.js';
 // #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 7ce9ba19..dba56892 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -51,7 +51,7 @@
 // #import {ThumbnailModel} from './metadata/thumbnail_model.m.js';
 // #import {MetadataModel} from './metadata/metadata_model.m.js';
 // #import {ContentMetadataProvider} from './metadata/content_metadata_provider.m.js';
-// #import {FilteredVolumeManager} from '../../../base/js/filtered_volume_manager.m.js';
+// #import {FilteredVolumeManager} from '../../common/js/filtered_volume_manager.m.js';
 // #import {LaunchParam} from './launch_param.m.js';
 // #import {contextMenuHandler} from 'chrome://resources/js/cr/ui/context_menu_handler.m.js';
 // #import {CommandButton} from './ui/commandbutton.m.js';
@@ -74,7 +74,7 @@
 // #import {SortMenuController} from './sort_menu_controller.m.js';
 // #import {ScanController} from './scan_controller.m.js';
 // #import {DriveDialogController} from './drive_dialog_controller.m.js';
-// #import {VolumeManagerCommon, AllowedPaths} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon, AllowedPaths} from '../../common/js/volume_manager_types.m.js';
 // #import {AppStateController} from './app_state_controller.m.js';
 // #import {DialogType} from './dialog_type.m.js';
 // #import {FileMetadataFormatter} from './ui/file_metadata_formatter.m.js';
@@ -903,9 +903,6 @@
     this.document_.documentElement.classList.add('files-ng');
     this.dialogDom_.classList.add('files-ng');
 
-    this.dialogDom_.classList.toggle(
-        'camera-folder-enabled', util.isFilesCameraFolderEnabled());
-
     chrome.fileManagerPrivate.isTabletModeEnabled(
         this.onTabletModeChanged_.bind(this));
     chrome.fileManagerPrivate.onTabletModeChanged.addListener(
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 fea8096..e6c2d912 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
@@ -26,7 +26,7 @@
 // #import {DirectoryTree, DirectoryItem} from './ui/directory_tree.m.js';
 // #import {EntryList} from '../../common/js/files_app_entry_types.m.js';
 // #import {contextMenuHandler} from 'chrome://resources/js/cr/ui/context_menu_handler.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util, str, strf} from '../../common/js/util.m.js';
 // #import {DialogType} from './dialog_type.m.js';
 // #import {List} from 'chrome://resources/js/cr/ui/list.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands_unittest.m.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands_unittest.m.js
index a1b6c3aa..4757e4e1 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands_unittest.m.js
@@ -4,10 +4,12 @@
 
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertArrayEquals, assertEquals, assertNotEquals, assertTrue} from 'chrome://test/chai_assert.js';
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockEntry} from '../../common/js/mock_entry.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
+
 import {CommandHandler, CommandUtil} from './file_manager_commands.m.js';
 import {FileTasks} from './file_tasks.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_selection.js b/ui/file_manager/file_manager/foreground/js/file_selection.js
index 2aedeb1d..dc34be4 100644
--- a/ui/file_manager/file_manager/foreground/js/file_selection.js
+++ b/ui/file_manager/file_manager/foreground/js/file_selection.js
@@ -8,7 +8,7 @@
 // #import {FileOperationManager} from '../../externs/background/file_operation_manager.m.js';
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
-// #import {AllowedPaths} from '../../../base/js/volume_manager_types.m.js';
+// #import {AllowedPaths} from '../../common/js/volume_manager_types.m.js';
 // #import {util} from '../../common/js/util.m.js';
 // #import {constants} from './constants.m.js';
 // #import {FileType} from '../../common/js/file_type.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 4a48cd5..cd8de1f8 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -20,7 +20,7 @@
 // #import {ProgressCenterItem, ProgressItemType, ProgressItemState} from '../../common/js/progress_center_common.m.js';
 // #import {FileTransferController} from './file_transfer_controller.m.js';
 // #import {FilesConfirmDialog} from './ui/files_confirm_dialog.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {FileType} from '../../common/js/file_type.m.js';
 // #import {constants} from './constants.m.js';
 // #import {util, strf, str} from '../../common/js/util.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.m.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.m.js
index bc8d3f8..29d76db 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.m.js
@@ -4,14 +4,14 @@
 
 import {assertArrayEquals, assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {createCrostiniForTest} from '../../background/js/mock_crostini.m.js';
 import {MockProgressCenter} from '../../background/js/mock_progress_center.m.js';
 import {metrics} from '../../common/js/metrics.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import {MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
 import {ProgressItemState} from '../../common/js/progress_center_common.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {ProgressCenter} from '../../externs/background/progress_center.m.js';
 import {EntryLocation} from '../../externs/entry_location.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index d6aa991..585f74d 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -19,7 +19,7 @@
 // #import {FileSelectionHandler} from './file_selection.m.js';
 // #import {DragSelector} from './ui/drag_selector.m.js';
 // #import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {DirectoryItem, DirectoryTree} from './ui/directory_tree.m.js';
 // #import {TreeItem} from 'chrome://resources/js/cr/ui/tree.m.js';
 // #import {ThumbnailLoader} from './thumbnail_loader.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.m.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.m.js
index 1bfe8d7b..fcc93297a 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.m.js
@@ -8,10 +8,10 @@
 import {queryRequiredElement} from 'chrome://resources/js/util.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {FileOperationManager} from '../../externs/background/file_operation_manager.m.js';
 import {importerHistoryInterfaces} from '../../externs/background/import_history.m.js';
 import {ProgressCenter} from '../../externs/background/progress_center.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.m.js b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.m.js
index 2f8806f5..67a14f12 100644
--- a/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/file_type_filters_controller_unittest.m.js
@@ -6,9 +6,9 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {EntryList, FakeEntryImpl} from '../../common/js/files_app_entry_types.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {FakeEntry} from '../../externs/files_app_entry_interfaces.m.js';
 
 import {DirectoryModel} from './directory_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
index 598fde0c..17f6c85 100644
--- a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
+++ b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {FilteredVolumeManager} from '../../../base/js/filtered_volume_manager.m.js';
+// #import {FilteredVolumeManager} from '../../common/js/filtered_volume_manager.m.js';
 // #import {util} from '../../common/js/util.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {AsyncUtil} from '../../common/js/async_util.m.js';
 // #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
index 26b39f1..ffa38af 100644
--- a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
@@ -9,7 +9,7 @@
 // #import {ProvidersMenu} from './ui/providers_menu.m.js';
 // #import {GearMenu} from './ui/gear_menu.m.js';
 // #import {MultiMenuButton} from './ui/multi_menu_button.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {DirectoryChangeEvent} from '../../externs/directory_change_event.m.js';
 // #import {str, util} from '../../common/js/util.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/holding_space_util.js b/ui/file_manager/file_manager/foreground/js/holding_space_util.js
index 435768c..8d20c9c 100644
--- a/ui/file_manager/file_manager/foreground/js/holding_space_util.js
+++ b/ui/file_manager/file_manager/foreground/js/holding_space_util.js
@@ -7,7 +7,7 @@
  */
 
 // clang-format off
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index fdb40a9..8581d8a6 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -18,7 +18,7 @@
 // #import {FileSelectionHandler} from './file_selection.m.js';
 // #import {util, strf, str} from '../../common/js/util.m.js';
 // #import {queryRequiredElement, getRequiredElement} from 'chrome://resources/js/util.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // #import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller_unittest.m.js b/ui/file_manager/file_manager/foreground/js/import_controller_unittest.m.js
index bdedf66..38e8859c 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller_unittest.m.js
@@ -5,12 +5,12 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {MockChromeStorageAPI, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {TestMediaScanner} from '../../background/js/mock_media_scanner.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
+import {MockChromeStorageAPI, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {mediaImportInterfaces} from '../../externs/background/media_import_handler.m.js';
 import {mediaScannerInterfaces} from '../../externs/background/media_scanner.m.js';
 import {VolumeInfo} from '../../externs/volume_info.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/launch_param.js b/ui/file_manager/file_manager/foreground/js/launch_param.js
index 541e33e..d0ca45a9 100644
--- a/ui/file_manager/file_manager/foreground/js/launch_param.js
+++ b/ui/file_manager/file_manager/foreground/js/launch_param.js
@@ -2,8 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// #import {AllowedPaths} from '../../../base/js/volume_manager_types.m.js';
+// clang-format off
+// #import {AllowedPaths} from '../../common/js/volume_manager_types.m.js';
 // #import {DialogType} from './dialog_type.m.js';
+// clang-format on
 
 /**
  * @typedef {{
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
index 41b82fe..1cd8d56 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader.js
@@ -7,7 +7,7 @@
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {ThumbnailModel} from './metadata/thumbnail_model.m.js';
 // #import {DirectoryModel} from './directory_model.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {LRUCache} from '../../common/js/lru_cache.m.js';
 // #import {ThumbnailLoader} from './thumbnail_loader.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.m.js b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.m.js
index 91496cc8..3fde04b 100644
--- a/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/list_thumbnail_loader_unittest.m.js
@@ -6,9 +6,9 @@
 import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {reportPromise, waitUntil} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockDirectoryEntry, MockEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise, waitUntil} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
 
 import {DirectoryModel} from './directory_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/main.m.js b/ui/file_manager/file_manager/foreground/js/main.m.js
index 2b9bf8f..095de5b 100644
--- a/ui/file_manager/file_manager/foreground/js/main.m.js
+++ b/ui/file_manager/file_manager/foreground/js/main.m.js
@@ -6,7 +6,7 @@
  * @fileoverview Start point for Files app.
  */
 
-import '../../../base/js/error_counter.m.js';
+import '../../common/js/error_counter.m.js';
 import './metrics_start.m.js';
 
 import {util} from '../../common/js/util.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index ef80577..1a647a5 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -21,7 +21,7 @@
 // "whatever.js". You should rerun gyp to let the build files know.
 //
 // error_counter.js must be loaded before all other scripts of the Files app.
-// <include src="../../../base/js/error_counter.js">
+// <include src="../../../file_manager/common/js/error_counter.js">
 //
 // metrics_base.js and metrics.js initiates load performance tracking
 // so we want to parse it as early as possible.
@@ -82,8 +82,8 @@
 // <include src="../../common/js/async_util.js">
 // <include src="../../common/js/file_type.js">
 // <include src="../../common/js/files_app_entry_types.js">
-// <include src="../../../base/js/volume_manager_types.js">
-// <include src="../../../base/js/app_util.js">
+// <include src="../../../file_manager/common/js/volume_manager_types.js">
+// <include src="../../../file_manager/common/js/app_util.js">
 // <include src="../../common/js/util.js">
 // <include src="../../common/js/progress_center_common.js">
 // <include src="../../common/js/storage_adapter.js">
@@ -190,7 +190,7 @@
 // <include src="ui/providers_menu.js">
 // <include src="ui/search_box.js">
 // <include src="main_window_component.js">
-// <include src="../../../base/js/filtered_volume_manager.js">
+// <include src="../../../file_manager/common/js/filtered_volume_manager.js">
 // <include src="webui_command_extender.js">
 
 // // For accurate load performance tracking place main.js should be
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index b0c2d90f..b69f6cf 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -10,7 +10,7 @@
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {FileManagerUI} from './ui/file_manager_ui.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {str, util} from '../../common/js/util.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // #import {DialogType} from './dialog_type.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
index 1725a0a..70e8512 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/metadata/BUILD.gn
@@ -121,7 +121,7 @@
     ":content_metadata_provider.m",
     ":metadata_request.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -191,8 +191,8 @@
     ":external_metadata_provider.m",
     ":metadata_request.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -215,7 +215,7 @@
     ":file_system_metadata_provider.m",
     ":metadata_request.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -424,7 +424,7 @@
     ":metadata_model.m",
     ":metadata_provider.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -515,7 +515,7 @@
     ":metadata_item.m",
     ":metadata_provider.m",
     ":metadata_request.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/webui/resources/js:assert.m",
   ]
@@ -531,8 +531,8 @@
     ":metadata_request.m",
     ":multi_metadata_provider.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
   ]
 }
@@ -557,7 +557,7 @@
     ":metadata_model.m",
     ":thumbnail_model.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.m.js
index b1be91e..b2a03cc 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.m.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 import {ContentMetadataProvider} from './content_metadata_provider.m.js';
 import {MetadataRequest} from './metadata_request.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.m.js
index 7908e70d..291c09b 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.m.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
-import {installMockChrome} from '../../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {installMockChrome} from '../../../common/js/mock_chrome.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 import {ExternalMetadataProvider} from './external_metadata_provider.m.js';
 import {MetadataRequest} from './metadata_request.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.m.js
index b18e415..2aa1833 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.m.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertEquals, assertTrue} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 import {FileSystemMetadataProvider} from './file_system_metadata_provider.m.js';
 import {MetadataRequest} from './metadata_request.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.m.js
index 4493879..0bad524b 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.m.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertEquals, assertThrows} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 import {MetadataModel} from './metadata_model.m.js';
 import {MetadataProvider} from './metadata_provider.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
index 541181a..702701c 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
@@ -9,7 +9,7 @@
 // #import {MetadataItem} from './metadata_item.m.js';
 // #import {MetadataProvider} from './metadata_provider.m.js';
 // #import {MetadataRequest} from './metadata_request.m.js';
-// #import * as wrappedVolumeManagerCommon from '../../../../base/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
+// #import * as wrappedVolumeManagerCommon from '../../../common/js/volume_manager_types.m.js'; const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 // #import {VolumeManager} from '../../../externs/volume_manager.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js
index 817223c..8743f55 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.m.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 import {assertArrayEquals, assertEquals, assertNotReached, assertTrue} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
-import * as wrappedVolumeManagerCommon from '../../../../base/js/volume_manager_types.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
+import * as wrappedVolumeManagerCommon from '../../../common/js/volume_manager_types.m.js';
 const {VolumeManagerCommon} = wrappedVolumeManagerCommon;
 import {ContentMetadataProvider} from './content_metadata_provider.m.js';
 import {ExternalMetadataProvider} from './external_metadata_provider.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.m.js b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.m.js
index f9a53c4..ac6628c 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model_unittest.m.js
@@ -4,7 +4,7 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 
 import {MetadataItem} from './metadata_item.m.js';
 import {MetadataModel} from './metadata_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/naming_controller.js b/ui/file_manager/file_manager/foreground/js/naming_controller.js
index 22a505e9..9a9b64a 100644
--- a/ui/file_manager/file_manager/foreground/js/naming_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/naming_controller.js
@@ -153,7 +153,9 @@
   }
 
   initiateRename() {
-    const item = this.listContainer_.currentList.ensureLeadItemExists();
+    const selectedIndex = this.listContainer_.selectionModel.selectedIndex;
+    const item =
+        this.listContainer_.currentList.getListItemByIndex(selectedIndex);
     if (!item) {
       return;
     }
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 9e96a28..27f15da 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -13,7 +13,7 @@
 // #import {util, str} from '../../common/js/util.m.js';
 // #import {FakeEntryImpl, VolumeEntry, EntryList} from '../../common/js/files_app_entry_types.m.js';
 // #import {assertNotReached} from 'chrome://resources/js/assert.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
index 5dac934..db252e46 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.m.js
@@ -5,14 +5,14 @@
 // clang-format off
 import {assertEquals, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise, waitUntil} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
 import {VolumeInfoImpl} from '../../background/js/volume_info_impl.m.js';
 import { EntryList,FakeEntryImpl} from '../../common/js/files_app_entry_types.m.js';
+import {MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import { MockFileEntry,MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise, waitUntil} from '../../common/js/test_error_reporting.m.js';
 import {util} from '../../common/js/util.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {FilesAppEntry} from '../../externs/files_app_entry_interfaces.m.js';
 
 import {AndroidAppListModel} from './android_app_list_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_uma.js b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
index 8b625c6b..7f951284 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_uma.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_uma.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/path_component.js b/ui/file_manager/file_manager/foreground/js/path_component.js
index 1bd4806..fdd35da1 100644
--- a/ui/file_manager/file_manager/foreground/js/path_component.js
+++ b/ui/file_manager/file_manager/foreground/js/path_component.js
@@ -4,7 +4,7 @@
 
 // clang-format off
 // #import {FilesAppEntry, FakeEntry} from '../../externs/files_app_entry_interfaces.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util, str} from '../../common/js/util.m.js';
 // clang-format on
 
@@ -158,7 +158,7 @@
         if (path === 'PvmDefault') {
           path = str('PLUGIN_VM_DIRECTORY_LABEL');
         }
-        if (util.isFilesCameraFolderEnabled() && path === 'Camera') {
+        if (path === 'Camera') {
           path = str('CAMERA_DIRECTORY_LABEL');
         }
       }
diff --git a/ui/file_manager/file_manager/foreground/js/providers_model.js b/ui/file_manager/file_manager/foreground/js/providers_model.js
index bb6ca381..2c894a0 100644
--- a/ui/file_manager/file_manager/foreground/js/providers_model.js
+++ b/ui/file_manager/file_manager/foreground/js/providers_model.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
 // clang-format on
diff --git a/ui/file_manager/file_manager/foreground/js/providers_model_unittest.m.js b/ui/file_manager/file_manager/foreground/js/providers_model_unittest.m.js
index 76c549a5..72173a3 100644
--- a/ui/file_manager/file_manager/foreground/js/providers_model_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/providers_model_unittest.m.js
@@ -4,12 +4,12 @@
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../background/js/mock_volume_manager.m.js';
 import {VolumeInfoImpl} from '../../background/js/volume_info_impl.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
 
 import {ProvidersModel} from './providers_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
index e90d744..8db09dc3 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -16,7 +16,7 @@
 // #import {ListContainer} from './ui/list_container.m.js';
 // #import {MetadataModel} from './metadata/metadata_model.m.js';
 // #import {CommandHandlerDeps} from '../../externs/command_handler_deps.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {ThumbnailLoader} from './thumbnail_loader.m.js';
 // #import {ImageLoaderClient} from '../../../image_loader/image_loader_client.m.js';
 // #import {LoadImageResponseStatus, LoadImageRequest} from '../../../image_loader/load_image_request.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
index d3af98a6..1ed0ade 100644
--- a/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
+++ b/ui/file_manager/file_manager/foreground/js/quick_view_uma.js
@@ -4,7 +4,7 @@
 
 // clang-format off
 // #import {VolumeManager} from '../../externs/volume_manager.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {metrics} from '../../common/js/metrics.m.js';
 // #import {DialogType} from './dialog_type.m.js';
 // #import {FileTasks} from './file_tasks.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/search_controller.js b/ui/file_manager/file_manager/foreground/js/search_controller.js
index 6570c7cd..ba71fc6 100644
--- a/ui/file_manager/file_manager/foreground/js/search_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/search_controller.js
@@ -10,7 +10,7 @@
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {LocationLine} from './ui/location_line.m.js';
 // #import {str, strf} from '../../common/js/util.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {SearchBox} from './ui/search_box.m.js';
 // clang-format on
 
diff --git a/ui/file_manager/file_manager/foreground/js/spinner_controller_unittest.m.js b/ui/file_manager/file_manager/foreground/js/spinner_controller_unittest.m.js
index 68afffe..ebf0cfce 100644
--- a/ui/file_manager/file_manager/foreground/js/spinner_controller_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/spinner_controller_unittest.m.js
@@ -5,7 +5,7 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 
 import {SpinnerController} from './spinner_controller.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.m.js b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.m.js
index 371ce45..386a297 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.m.js
@@ -7,13 +7,13 @@
 import {Command} from 'chrome://resources/js/cr/ui/command.m.js';
 import {assertEquals, assertNotReached} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome} from '../../../base/js/mock_chrome.m.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
 import {createCrostiniForTest} from '../../background/js/mock_crostini.m.js';
 import {metrics} from '../../common/js/metrics.m.js';
+import {installMockChrome} from '../../common/js/mock_chrome.m.js';
 import {MockFileEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
 import {util} from '../../common/js/util.m.js';
+import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 import {ProgressCenter} from '../../externs/background/progress_center.m.js';
 import {VolumeManager} from '../../externs/volume_manager.m.js';
 
diff --git a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.m.js b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.m.js
index a72718b..dcee2f1 100644
--- a/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/thumbnail_loader_unittest.m.js
@@ -3,10 +3,12 @@
 // found in the LICENSE file.
 
 import {assertEquals, assertTrue} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+
 import {ImageLoaderClient} from '../../../image_loader/image_loader_client.m.js';
 import {LoadImageRequest} from '../../../image_loader/load_image_request.m.js';
 import {MockEntry, MockFileSystem} from '../../common/js/mock_entry.m.js';
+import {reportPromise} from '../../common/js/test_error_reporting.m.js';
+
 import {ThumbnailLoader} from './thumbnail_loader.m.js';
 
 function getLoadTarget(entry, metadata) {
diff --git a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
index e62bba5..2c2d619 100644
--- a/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/toolbar_controller.js
@@ -9,7 +9,7 @@
 // #import {DirectoryModel} from './directory_model.m.js';
 // #import {LocationLine} from './ui/location_line.m.js';
 // #import {ListContainer} from './ui/list_container.m.js';
-// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../common/js/volume_manager_types.m.js';
 // #import {util, str, strf} from '../../common/js/util.m.js';
 // #import {FileSelectionHandler} from './file_selection.m.js';
 // #import {Command} from 'chrome://resources/js/cr/ui/command.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index cc37057c..d8662c3 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -203,8 +203,8 @@
 
 js_library("banners") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/foreground/js:directory_model",
     "//ui/file_manager/file_manager/foreground/js:holding_space_util",
     "//ui/webui/resources/js:assert",
@@ -219,8 +219,8 @@
     "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/banners.m.js",
   ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/foreground/js:constants.m",
@@ -348,8 +348,8 @@
 
 js_library("directory_tree") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/foreground/js:directory_model",
     "//ui/file_manager/file_manager/foreground/js:navigation_list_model",
     "//ui/file_manager/file_manager/foreground/js/metadata:metadata_model",
@@ -362,10 +362,10 @@
 js_library("directory_tree.m") {
   sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/ui/directory_tree.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:file_type.m",
     "//ui/file_manager/file_manager/common/js:metrics.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:files_app_entry_interfaces.m",
     "//ui/file_manager/file_manager/externs:volume_info.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
@@ -392,13 +392,13 @@
   deps = [
     ":directory_tree.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
-    "//ui/file_manager/base/js:test_error_reporting.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
     "//ui/file_manager/file_manager/common/js:mock_entry.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs/background:file_operation_manager.m",
     "//ui/file_manager/file_manager/foreground/js:directory_model.m",
     "//ui/file_manager/file_manager/foreground/js:fake_android_app_list_model.m",
@@ -530,7 +530,7 @@
   deps = [
     ":file_manager_dialog_base.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/webui/resources/js:assert.m",
   ]
 }
@@ -608,8 +608,8 @@
     ":progress_center_panel.m",
     ":providers_menu.m",
     ":search_box.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs:volume_manager.m",
     "//ui/file_manager/file_manager/foreground/elements:files_password_dialog.m",
     "//ui/file_manager/file_manager/foreground/elements:files_toast.m",
@@ -748,9 +748,9 @@
     ":file_table.m",
     ":file_table_list.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/background/js:mock_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/file_manager/file_manager/externs/background:import_history.m",
     "//ui/file_manager/file_manager/foreground/js:directory_model.m",
     "//ui/file_manager/file_manager/foreground/js:file_list_model.m",
@@ -774,7 +774,7 @@
   deps = [
     ":file_tap_handler.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
@@ -925,10 +925,10 @@
 
 js_library("location_line") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:files_app_entry_types",
     "//ui/file_manager/file_manager/common/js:metrics",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
     "//ui/file_manager/file_manager/foreground/js:path_component",
   ]
diff --git a/ui/file_manager/file_manager/foreground/js/ui/banners.js b/ui/file_manager/file_manager/foreground/js/ui/banners.js
index 1570eb84..44c9189 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/banners.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/banners.js
@@ -6,7 +6,7 @@
 // #import {VolumeInfo} from '../../../externs/volume_info.m.js';
 // #import {VolumeManager} from '../../../externs/volume_manager.m.js';
 // #import {DirectoryModel} from '../directory_model.m.js';
-// #import {VolumeManagerCommon} from '../../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../../common/js/volume_manager_types.m.js';
 // #import {constants} from '../constants.m.js';
 // #import {HoldingSpaceUtil} from '../holding_space_util.m.js';
 // #import {queryRequiredElement} from 'chrome://resources/js/util.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 429dd6a..74bfc07 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -17,7 +17,7 @@
 // #import {contextMenuHandler} from 'chrome://resources/js/cr/ui/context_menu_handler.m.js';
 // #import {constants} from '../constants.m.js';
 // #import {TreeItem, Tree} from 'chrome://resources/js/cr/ui/tree.m.js';
-// #import {VolumeManagerCommon} from '../../../../base/js/volume_manager_types.m.js';
+// #import {VolumeManagerCommon} from '../../../common/js/volume_manager_types.m.js';
 // #import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
 // #import {dispatchSimpleEvent, getPropertyDescriptor, PropertyKind} from 'chrome://resources/js/cr.m.js';
 // #import {metrics} from '../../../common/js/metrics.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.m.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.m.js
index 114deff..18724863 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree_unittest.m.js
@@ -6,14 +6,14 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {assertArrayEquals,assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {installMockChrome, MockCommandLinePrivate} from '../../../../base/js/mock_chrome.m.js';
-import {reportPromise, waitUntil} from '../../../../base/js/test_error_reporting.m.js';
-import {VolumeManagerCommon} from '../../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../../background/js/mock_volume_manager.m.js';
 import {EntryList} from '../../../common/js/files_app_entry_types.m.js';
 import {metrics} from '../../../common/js/metrics.m.js';
+import {installMockChrome, MockCommandLinePrivate} from '../../../common/js/mock_chrome.m.js';
 import {MockDirectoryEntry} from '../../../common/js/mock_entry.m.js';
+import {reportPromise, waitUntil} from '../../../common/js/test_error_reporting.m.js';
 import {str} from '../../../common/js/util.m.js';
+import {VolumeManagerCommon} from '../../../common/js/volume_manager_types.m.js';
 import {FileOperationManager} from '../../../externs/background/file_operation_manager.m.js';
 import {DirectoryModel} from '../directory_model.m.js';
 import {createFakeAndroidAppListModel} from '../fake_android_app_list_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.m.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.m.js
index bb352941..e4872ea 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_dialog_base_unittest.m.js
@@ -4,7 +4,7 @@
 
 import {assertInstanceof} from 'chrome://resources/js/assert.m.js';
 import {assertFalse} from 'chrome://test/chai_assert.js';
-import {waitUntil} from '../../../../base/js/test_error_reporting.m.js';
+import {waitUntil} from '../../../common/js/test_error_reporting.m.js';
 import {FileManagerDialogBase} from './file_manager_dialog_base.m.js';
 
 export function setUp() {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 62462ac..823b1a2 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -27,7 +27,7 @@
 // #import {contextMenuHandler} from 'chrome://resources/js/cr/ui/context_menu_handler.m.js';
 // #import {LocationLine} from './location_line.m.js';
 // #import {ListContainer} from './list_container.m.js';
-// #import {AllowedPaths} from '../../../../base/js/volume_manager_types.m.js';
+// #import {AllowedPaths} from '../../../common/js/volume_manager_types.m.js';
 // #import {ActionsSubmenu} from './actions_submenu.m.js';
 // #import {ProvidersMenu} from './providers_menu.m.js';
 // #import {ComboButton} from './combobutton.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table_list_unittest.m.js b/ui/file_manager/file_manager/foreground/js/ui/file_table_list_unittest.m.js
index bd473f7..ef13a81 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table_list_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table_list_unittest.m.js
@@ -4,9 +4,9 @@
 
 import {assertEquals, assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
 
-import {VolumeManagerCommon} from '../../../../base/js/volume_manager_types.m.js';
 import {MockVolumeManager} from '../../../background/js/mock_volume_manager.m.js';
 import {FakeEntryImpl} from '../../../common/js/files_app_entry_types.m.js';
+import {VolumeManagerCommon} from '../../../common/js/volume_manager_types.m.js';
 import {importerHistoryInterfaces} from '../../../externs/background/import_history.m.js';
 import {DirectoryModel} from '../directory_model.m.js';
 import {FileListModel} from '../file_list_model.m.js';
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.m.js b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.m.js
index 6fd878e..a156333 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.m.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_tap_handler_unittest.m.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../common/js/test_error_reporting.m.js';
 import {FileTapHandler} from './file_tap_handler.m.js';
 
 /** @type {!FileTapHandler} handler the handler. */
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index aaa5db2..f7f7d68 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -11,7 +11,6 @@
 loadTimeData.overrideValues({
   'COPY_IMAGE_ENABLED': false,
   'CROSTINI_ENABLED': true,
-  'FILES_CAMERA_FOLDER_ENABLED': false,
   'FILES_NG_ENABLED': true,
   'FILES_SINGLE_PARTITION_FORMAT_ENABLED': false,
   'FILES_TRASH_ENABLED': true,
diff --git a/ui/file_manager/file_manager/test/scripts/create_test_main.py b/ui/file_manager/file_manager/test/scripts/create_test_main.py
index 24b7057..0183ba09 100755
--- a/ui/file_manager/file_manager/test/scripts/create_test_main.py
+++ b/ui/file_manager/file_manager/test/scripts/create_test_main.py
@@ -168,7 +168,7 @@
     'common/js/files_app_entry_types.js',
     'common/js/util.js',
     'common/js/mock_entry.js',
-    '../base/js/volume_manager_types.js',
+    '../file_manager/common/js/volume_manager_types.js',
     'background/js/volume_info_impl.js',
     'background/js/volume_info_list_impl.js',
     'background/js/volume_manager_impl.js',
diff --git a/ui/file_manager/gallery/js/BUILD.gn b/ui/file_manager/gallery/js/BUILD.gn
index bc612db..1480d67 100644
--- a/ui/file_manager/gallery/js/BUILD.gn
+++ b/ui/file_manager/gallery/js/BUILD.gn
@@ -67,8 +67,8 @@
 js_unittest("entry_list_watcher_unittest") {
   deps = [
     ":entry_list_watcher",
-    "//ui/file_manager/base/js:test_error_reporting",
     "//ui/file_manager/file_manager/common/js:mock_entry",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
 }
 
@@ -81,8 +81,8 @@
     ":gallery_constants",
     ":gallery_item",
     ":thumbnail_mode",
-    "//ui/file_manager/base/js:app_util",
-    "//ui/file_manager/base/js:filtered_volume_manager",
+    "//ui/file_manager/file_manager/common/js:app_util",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager",
     "//ui/file_manager/file_manager/common/js:util",
     "//ui/file_manager/file_manager/foreground/js/ui:files_confirm_dialog",
     "//ui/file_manager/gallery/js:slide_mode",
@@ -108,7 +108,7 @@
   deps = [
     ":gallery_data_model",
     ":mock_gallery_item",
-    "//ui/file_manager/base/js:test_error_reporting",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
 }
 
@@ -129,7 +129,7 @@
   deps = [
     ":gallery_item",
     ":mock_gallery_item",
-    "//ui/file_manager/base/js:test_error_reporting",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
 }
 
@@ -139,9 +139,9 @@
 
 js_library("gallery_util") {
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
     "//ui/file_manager/file_manager/common/js:file_type",
     "//ui/file_manager/file_manager/common/js:util",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/file_manager/externs:volume_manager",
   ]
 }
@@ -149,8 +149,8 @@
 js_unittest("gallery_util_unittest") {
   deps = [
     ":gallery_util",
-    "//ui/file_manager/base/js:test_error_reporting",
     "//ui/file_manager/file_manager/common/js:mock_entry",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
 }
 
@@ -210,7 +210,7 @@
 js_unittest("slide_mode_unittest") {
   deps = [
     ":slide_mode",
-    "//ui/file_manager/base/js:test_error_reporting",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting",
   ]
 }
 
diff --git a/ui/file_manager/gallery/js/gallery_scripts.js b/ui/file_manager/gallery/js/gallery_scripts.js
index 94d7d84..b9ad204 100644
--- a/ui/file_manager/gallery/js/gallery_scripts.js
+++ b/ui/file_manager/gallery/js/gallery_scripts.js
@@ -44,12 +44,12 @@
 
 // <include src="../../file_manager/common/js/async_util.js">
 // <include src="../../file_manager/common/js/file_type.js">
-// <include src="../../base/js/app_util.js">
+// <include src="../../file_manager/common/js/app_util.js">
 
 /* TODO(tapted): Remove the util.js dependency */
 // <include src="../../file_manager/common/js/util.js">
 
-// <include src="../../base/js/volume_manager_types.js">
+// <include src="../../file_manager/common/js/volume_manager_types.js">
 // <include
 // src="../../file_manager/foreground/js/metadata/content_metadata_provider.js">
 // <include src="../../file_manager/foreground/js/metadata/exif_constants.js">
@@ -69,7 +69,7 @@
 // src="../../file_manager/foreground/js/ui/file_manager_dialog_base.js">
 // <include src="../../file_manager/foreground/js/ui/files_alert_dialog.js">
 // <include src="../../file_manager/foreground/js/ui/files_confirm_dialog.js">
-// <include src="../../base/js/filtered_volume_manager.js">
+// <include src="../../file_manager/common/js/filtered_volume_manager.js">
 
 // <include src="image_editor/image_util.js">
 // <include src="image_editor/viewport.js">
diff --git a/ui/file_manager/gallery/js/image_editor/BUILD.gn b/ui/file_manager/gallery/js/image_editor/BUILD.gn
index 5870cd61..302085e 100644
--- a/ui/file_manager/gallery/js/image_editor/BUILD.gn
+++ b/ui/file_manager/gallery/js/image_editor/BUILD.gn
@@ -165,7 +165,7 @@
     ":image_encoder.m",
     ":test_util.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
     "//ui/file_manager/file_manager/foreground/js/metadata:metadata_item.m",
   ]
   externs_list =
diff --git a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.m.js b/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.m.js
index 755ecf5..5a3ea420 100644
--- a/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.m.js
+++ b/ui/file_manager/gallery/js/image_editor/image_encoder_unittest.m.js
@@ -5,7 +5,7 @@
 /* eslint-disable no-var */
 
 import {assertEquals, assertThrows} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../../../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../../../file_manager/common/js/test_error_reporting.m.js';
 import {MetadataItem} from '../../../file_manager/foreground/js/metadata/metadata_item.m.js';
 import {ImageEncoder} from './image_encoder.m.js';
 import {getSampleCanvas} from './test_util.m.js';
diff --git a/ui/file_manager/image_loader/BUILD.gn b/ui/file_manager/image_loader/BUILD.gn
index 94cccce1..fe3ac7d 100644
--- a/ui/file_manager/image_loader/BUILD.gn
+++ b/ui/file_manager/image_loader/BUILD.gn
@@ -163,7 +163,7 @@
     ":image_loader_client.m",
     ":load_image_request.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:test_error_reporting.m",
+    "//ui/file_manager/file_manager/common/js:test_error_reporting.m",
   ]
 }
 
diff --git a/ui/file_manager/image_loader/image_loader_client_unittest.m.js b/ui/file_manager/image_loader/image_loader_client_unittest.m.js
index f57947ec..e65808d 100644
--- a/ui/file_manager/image_loader/image_loader_client_unittest.m.js
+++ b/ui/file_manager/image_loader/image_loader_client_unittest.m.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertFalse, assertTrue} from 'chrome://test/chai_assert.js';
-import {reportPromise} from '../base/js/test_error_reporting.m.js';
+import {reportPromise} from '../file_manager/common/js/test_error_reporting.m.js';
 import {ImageLoaderClient} from './image_loader_client.m.js';
 import {LoadImageRequest, LoadImageResponse, LoadImageResponseStatus} from './load_image_request.m.js';
 
diff --git a/ui/file_manager/integration_tests/BUILD.gn b/ui/file_manager/integration_tests/BUILD.gn
index 60f6800d..10d426fb 100644
--- a/ui/file_manager/integration_tests/BUILD.gn
+++ b/ui/file_manager/integration_tests/BUILD.gn
@@ -10,7 +10,7 @@
   deps = [
     ":remote_call",
     ":test_util",
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
   ]
 }
 
diff --git a/ui/file_manager/integration_tests/file_manager/BUILD.gn b/ui/file_manager/integration_tests/file_manager/BUILD.gn
index f93a44f..7f963c8a 100644
--- a/ui/file_manager/integration_tests/file_manager/BUILD.gn
+++ b/ui/file_manager/integration_tests/file_manager/BUILD.gn
@@ -56,7 +56,7 @@
 js_library("background") {
   testonly = true
   deps = [
-    "//ui/file_manager/base/js:volume_manager_types",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types",
     "//ui/file_manager/integration_tests:remote_call",
     "//ui/file_manager/integration_tests:test_util",
   ]
@@ -64,9 +64,7 @@
 
 js_library("android_photos") {
   testonly = true
-  deps = [
-    ":background",
-  ]
+  deps = [ ":background" ]
 }
 
 js_library("breadcrumbs") {
diff --git a/ui/file_manager/integration_tests/file_manager/file_list.js b/ui/file_manager/integration_tests/file_manager/file_list.js
index 9424d6b..0def9b7c 100644
--- a/ui/file_manager/integration_tests/file_manager/file_list.js
+++ b/ui/file_manager/integration_tests/file_manager/file_list.js
@@ -358,6 +358,60 @@
   };
 
   /**
+   * Tests that in selection mode, the rename operation is applied to the
+   * selected item, as seen by the selection model, rather than the lead item.
+   * The lead and the selected item(s) are different when we deselect a file
+   * list item in selection mode. crbug.com/1094260
+   */
+  testcase.fileListRenameSelectedItem = async () => {
+    const appId = await setupAndWaitUntilReady(
+        RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET, []);
+
+    // Select 2 items.
+    await remoteCall.waitAndClickElement(
+        appId, '#file-list [file-name="hello.txt"]');
+    await remoteCall.waitAndClickElement(
+        appId, '#file-list [file-name="world.ogv"]', {ctrl: true});
+
+    // Deselect first item.
+    await remoteCall.waitAndClickElement(
+        appId, '#file-list [file-name="hello.txt"]', {ctrl: true});
+
+    // Check: the first item should have the lead state.
+    const item = await remoteCall.waitForElement(
+        appId, '#file-list li:not([selected])[file-name="hello.txt"]');
+    chrome.test.assertTrue('lead' in item.attributes);
+
+    // Check: selection should be on the second item.
+    await remoteCall.waitForElement(
+        appId, '#file-list li[selected][file-name="world.ogv"]');
+
+    // Press Ctrl+Enter key to rename the selected file.
+    const key = ['#file-list', 'Enter', true, false, false];
+    chrome.test.assertTrue(
+        await remoteCall.callRemoteTestUtil('fakeKeyDown', appId, key));
+
+    // Check: the renaming text input should be shown in the file list.
+    const textInput = '#file-list .table-row[renaming] input.rename';
+    await remoteCall.waitForElement(appId, textInput);
+
+    // Type new file name.
+    await remoteCall.callRemoteTestUtil(
+        'inputText', appId, [textInput, 'New File Name.txt']);
+
+    // Send Enter key to the text input.
+    const key2 = [textInput, 'Enter', false, false, false];
+    chrome.test.assertTrue(
+        await remoteCall.callRemoteTestUtil('fakeKeyDown', appId, key2));
+
+    // Check: the selected file should have been renamed.
+    await remoteCall.waitForElementLost(
+        appId, '#file-list [file-name="world.ogv"]');
+    await remoteCall.waitForElement(
+        appId, '#file-list li[selected][file-name="New File Name.txt"]');
+  };
+
+  /**
    * Tests that user can rename a file/folder after using "select all" without
    * having selected any file previously.
    */
diff --git a/ui/file_manager/video_player/js/BUILD.gn b/ui/file_manager/video_player/js/BUILD.gn
index eb3f899..179d4d9 100644
--- a/ui/file_manager/video_player/js/BUILD.gn
+++ b/ui/file_manager/video_player/js/BUILD.gn
@@ -104,7 +104,7 @@
 
 js_library("video_player_native_controls") {
   deps = [
-    "//ui/file_manager/base/js:app_util",
+    "//ui/file_manager/file_manager/common/js:app_util",
     "//ui/file_manager/file_manager/externs:file_manager_private",
     "//ui/webui/resources/js:load_time_data",
     "//ui/webui/resources/js:util",
@@ -115,7 +115,7 @@
 js_library("video_player_native_controls.m") {
   sources = [ "$root_gen_dir/ui/file_manager/video_player/js/video_player_native_controls.m.js" ]
   deps = [
-    "//ui/file_manager/base/js:app_util.m",
+    "//ui/file_manager/file_manager/common/js:app_util.m",
     "//ui/webui/resources/cr_elements/cr_toast:cr_toast.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:load_time_data.m",
@@ -131,7 +131,7 @@
   deps = [
     ":video_player_native_controls.m",
     "//chrome/test/data/webui:chai_assert",
-    "//ui/file_manager/base/js:mock_chrome.m",
+    "//ui/file_manager/file_manager/common/js:mock_chrome.m",
   ]
 }
 
@@ -140,8 +140,8 @@
     ":error_util",
     ":video_player_metrics",
     ":video_player_native_controls",
-    "//ui/file_manager/base/js:app_util",
-    "//ui/file_manager/base/js:filtered_volume_manager",
+    "//ui/file_manager/file_manager/common/js:app_util",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager",
     "//ui/file_manager/file_manager/common/js:metrics_base",
     "//ui/file_manager/file_manager/common/js:util",
     "//ui/webui/resources/js/cr/ui:menu",
@@ -156,10 +156,10 @@
     ":error_util.m",
     ":video_player_metrics.m",
     ":video_player_native_controls.m",
-    "//ui/file_manager/base/js:app_util.m",
-    "//ui/file_manager/base/js:filtered_volume_manager.m",
-    "//ui/file_manager/base/js:volume_manager_types.m",
+    "//ui/file_manager/file_manager/common/js:app_util.m",
+    "//ui/file_manager/file_manager/common/js:filtered_volume_manager.m",
     "//ui/file_manager/file_manager/common/js:util.m",
+    "//ui/file_manager/file_manager/common/js:volume_manager_types.m",
     "//ui/webui/resources/js:assert.m",
     "//ui/webui/resources/js:load_time_data.m",
   ]
diff --git a/ui/file_manager/video_player/js/video_player.js b/ui/file_manager/video_player/js/video_player.js
index f833549..681a8bc 100644
--- a/ui/file_manager/video_player/js/video_player.js
+++ b/ui/file_manager/video_player/js/video_player.js
@@ -6,9 +6,9 @@
 // #import './error_util.m.js';
 // #import {util} from '../../file_manager/common/js/util.m.js';
 // #import {assert} from 'chrome://resources/js/assert.m.js';
-// #import {appUtil} from '../../base/js/app_util.m.js';
-// #import {AllowedPaths} from '../../base/js/volume_manager_types.m.js';
-// #import {FilteredVolumeManager} from '../../base/js/filtered_volume_manager.m.js';
+// #import {appUtil} from '../../file_manager/common/js/app_util.m.js';
+// #import {AllowedPaths} from '../../file_manager/common/js/volume_manager_types.m.js';
+// #import {FilteredVolumeManager} from '../../file_manager/common/js/filtered_volume_manager.m.js';
 // #import {NativeControlsVideoPlayer} from './video_player_native_controls.m.js';
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 // #import {metrics} from './video_player_metrics.m.js';
diff --git a/ui/file_manager/video_player/js/video_player_native_controls.js b/ui/file_manager/video_player/js/video_player_native_controls.js
index 9048f598..ebd45e7 100644
--- a/ui/file_manager/video_player/js/video_player_native_controls.js
+++ b/ui/file_manager/video_player/js/video_player_native_controls.js
@@ -4,7 +4,7 @@
 
 // clang-format off
 // #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
-// #import {appUtil} from '../../base/js/app_util.m.js';
+// #import {appUtil} from '../../file_manager/common/js/app_util.m.js';
 // #import {getRequiredElement, queryRequiredElement} from 'chrome://resources/js/util.m.js';
 // #import {assertInstanceof} from 'chrome://resources/js/assert.m.js';
 // #import 'chrome://resources/cr_elements/cr_toast/cr_toast.m.js';
diff --git a/ui/file_manager/video_player/js/video_player_native_controls_unittest.m.js b/ui/file_manager/video_player/js/video_player_native_controls_unittest.m.js
index f2ff1cb..323fb663 100644
--- a/ui/file_manager/video_player/js/video_player_native_controls_unittest.m.js
+++ b/ui/file_manager/video_player/js/video_player_native_controls_unittest.m.js
@@ -4,7 +4,7 @@
 
 import {assertEquals} from 'chrome://test/chai_assert.js';
 
-import {MockChromeStorageAPI} from '../../base/js/mock_chrome.m.js';
+import {MockChromeStorageAPI} from '../../file_manager/common/js/mock_chrome.m.js';
 
 import {NativeControlsVideoPlayer} from './video_player_native_controls.m.js';
 
diff --git a/ui/file_manager/video_player/js/video_player_scripts.js b/ui/file_manager/video_player/js/video_player_scripts.js
index d062ba1a..7622829 100644
--- a/ui/file_manager/video_player/js/video_player_scripts.js
+++ b/ui/file_manager/video_player/js/video_player_scripts.js
@@ -31,13 +31,13 @@
 
 // <include src="../../file_manager/common/js/async_util.js">
 // <include src="../../file_manager/common/js/file_type.js">
-// <include src="../../base/js/app_util.js">
+// <include src="../../file_manager/common/js/app_util.js">
 
 /* TODO(tapted): Remove the util.js dependency */
 // <include src="../../file_manager/common/js/util.js">
 
-// <include src="../../base/js/volume_manager_types.js">
-// <include src="../../base/js/filtered_volume_manager.js">
+// <include src="../../file_manager/common/js/volume_manager_types.js">
+// <include src="../../file_manager/common/js/filtered_volume_manager.js">
 
 // <include src="video_player_native_controls.js">
 // <include src="video_player.js">
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index d39757a7..181c0c5 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -928,6 +928,7 @@
 if (is_android) {
   generate_jni("gfx_jni_headers") {
     sources = [
+      "../android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java",
       "../android/java/src/org/chromium/ui/gfx/Animation.java",
       "../android/java/src/org/chromium/ui/gfx/BitmapHelper.java",
       "../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java",
diff --git a/ui/gfx/rendering_pipeline.cc b/ui/gfx/rendering_pipeline.cc
index 6790edbf..a0842f94 100644
--- a/ui/gfx/rendering_pipeline.cc
+++ b/ui/gfx/rendering_pipeline.cc
@@ -129,7 +129,6 @@
  public:
   explicit RenderingPipelineImpl(const char* pipeline_type)
       : pipeline_type_(pipeline_type) {
-    RenderingStageScheduler::EnsureInitialized();
     DETACH_FROM_THREAD(bound_thread_);
   }
   ~RenderingPipelineImpl() override { TearDown(); }
diff --git a/ui/gfx/rendering_stage_scheduler.cc b/ui/gfx/rendering_stage_scheduler.cc
index 58c365c..b13643c9 100644
--- a/ui/gfx/rendering_stage_scheduler.cc
+++ b/ui/gfx/rendering_stage_scheduler.cc
@@ -5,118 +5,39 @@
 #include "ui/gfx/rendering_stage_scheduler.h"
 
 #include "base/logging.h"
-#include "base/native_library.h"
 #include "base/no_destructor.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
-
-#include <dlfcn.h>
-#include <sys/types.h>
-
-extern "C" {
-
-typedef struct APowerManager APowerManager;
-
-using pAPower_acquireManager = APowerManager* (*)();
-using pAPower_createThreadGroup = int64_t (*)(APowerManager* manager,
-                                              pid_t* threadIds,
-                                              size_t numThreadIds,
-                                              uint64_t desiredDurationMicros);
-using pAPower_destroyThreadGroup =
-    void (*)(APowerManager* manager, int64_t /* ThreadGroupId */ threadGroup);
-using pAPower_updateThreadGroupDesiredDuration =
-    void (*)(APowerManager* manager,
-             int64_t /* ThreadGroupId */ threadGroup,
-             uint64_t desiredDurationMicros);
-using pAPower_reportThreadGroupDuration =
-    void (*)(APowerManager* manager,
-             int64_t /* ThreadGroupId */ threadGroup,
-             uint64_t actualDurationMicros);
-}
-
+#include "base/android/jni_array.h"
+#include "base/android/scoped_java_ref.h"
+#include "ui/gfx/gfx_jni_headers/AdpfRenderingStageScheduler_jni.h"
 #endif  // OS_ANDROID
 
 namespace gfx {
 namespace {
-
 #if defined(OS_ANDROID)
 
-#define LOAD_FUNCTION(lib, func)                                \
-  do {                                                          \
-    func##Fn = reinterpret_cast<p##func>(                       \
-        base::GetFunctionPointerFromNativeLibrary(lib, #func)); \
-    if (!func##Fn) {                                            \
-      supported = false;                                        \
-      LOG(ERROR) << "Unable to load function " << #func;        \
-    }                                                           \
-  } while (0)
-
-struct AdpfMethods {
-  static const AdpfMethods& Get() {
-    static const base::NoDestructor<AdpfMethods> instance;
-    return *instance;
-  }
-
-  AdpfMethods() {
-    base::NativeLibraryLoadError error;
-    base::NativeLibrary main_dl_handle =
-        base::LoadNativeLibrary(base::FilePath("libandroid.so"), &error);
-    if (!main_dl_handle) {
-      LOG(ERROR) << "Couldnt load libandroid.so: " << error.ToString();
-      supported = false;
-      return;
-    }
-
-    LOAD_FUNCTION(main_dl_handle, APower_acquireManager);
-    LOAD_FUNCTION(main_dl_handle, APower_createThreadGroup);
-    LOAD_FUNCTION(main_dl_handle, APower_destroyThreadGroup);
-    LOAD_FUNCTION(main_dl_handle, APower_updateThreadGroupDesiredDuration);
-    LOAD_FUNCTION(main_dl_handle, APower_reportThreadGroupDuration);
-  }
-
-  ~AdpfMethods() = default;
-
-  bool supported = true;
-  pAPower_acquireManager APower_acquireManagerFn;
-  pAPower_createThreadGroup APower_createThreadGroupFn;
-  pAPower_destroyThreadGroup APower_destroyThreadGroupFn;
-  pAPower_updateThreadGroupDesiredDuration
-      APower_updateThreadGroupDesiredDurationFn;
-  pAPower_reportThreadGroupDuration APower_reportThreadGroupDurationFn;
-};
-
-APowerManager* GetPowerManager() {
-  static APowerManager* power_manager =
-      AdpfMethods::Get().supported
-          ? AdpfMethods::Get().APower_acquireManagerFn()
-          : nullptr;
-  return power_manager;
-}
-
 class RenderingStageSchedulerAdpf : public RenderingStageScheduler {
  public:
   RenderingStageSchedulerAdpf(const char* pipeline_type,
                               std::vector<base::PlatformThreadId> threads,
                               base::TimeDelta desired_duration)
       : pipeline_type_(pipeline_type), desired_duration_(desired_duration) {
-    static_assert(sizeof(base::PlatformThreadId) == sizeof(pid_t),
+    static_assert(sizeof(base::PlatformThreadId) == sizeof(jint),
                   "thread id types incompatible");
-
-    if (!GetPowerManager())
-      return;
-
-    id_ = AdpfMethods::Get().APower_createThreadGroupFn(
-        GetPowerManager(), threads.data(), threads.size(),
-        desired_duration.InMicroseconds());
+    JNIEnv* env = base::android::AttachCurrentThread();
+    j_object_ = Java_AdpfRenderingStageScheduler_create(
+        env, base::android::ToJavaIntArray(env, threads),
+        desired_duration_.InNanoseconds());
   }
 
   ~RenderingStageSchedulerAdpf() override {
-    if (!GetPowerManager())
+    if (!j_object_)
       return;
-
-    AdpfMethods::Get().APower_destroyThreadGroupFn(GetPowerManager(), id_);
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_AdpfRenderingStageScheduler_destroy(env, j_object_);
   }
 
   void ReportCpuCompletionTime(base::TimeDelta actual_duration) override {
@@ -125,30 +46,23 @@
         TRACE_EVENT_SCOPE_THREAD, "pipeline_type", pipeline_type_,
         "utilization_percentage",
         static_cast<int>(actual_duration * 100 / desired_duration_));
-
-    if (!GetPowerManager())
+    if (!j_object_)
       return;
-
-    AdpfMethods::Get().APower_reportThreadGroupDurationFn(
-        GetPowerManager(), id_, actual_duration.InMicroseconds());
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_AdpfRenderingStageScheduler_reportCpuCompletionTime(
+        env, j_object_, actual_duration.InNanoseconds());
   }
 
  private:
-  int64_t id_;
   const char* pipeline_type_;
   const base::TimeDelta desired_duration_;
+  base::android::ScopedJavaGlobalRef<jobject> j_object_;
 };
 
 #endif  // OS_ANDROID
 
 }  // namespace
 
-void RenderingStageScheduler::EnsureInitialized() {
-#if defined(OS_ANDROID)
-  AdpfMethods::Get();
-#endif
-}
-
 std::unique_ptr<RenderingStageScheduler> RenderingStageScheduler::CreateAdpf(
     const char* pipeline_type,
     std::vector<base::PlatformThreadId> threads,
diff --git a/ui/ozone/platform/drm/gpu/drm_device.cc b/ui/ozone/platform/drm/gpu/drm_device.cc
index af6db3b..6e262e2 100644
--- a/ui/ozone/platform/drm/gpu/drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/drm_device.cc
@@ -567,8 +567,24 @@
     id = page_flip_manager_->GetNextId();
   }
 
-  if (!drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
-                           reinterpret_cast<void*>(id))) {
+  int result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+                                   reinterpret_cast<void*>(id));
+  if (result && errno == EBUSY && (flags & DRM_MODE_ATOMIC_NONBLOCK)) {
+    VLOG(1) << "Nonblocking atomic commit failed with EBUSY, retry without "
+               "nonblock";
+    // There have been cases where we get back EBUSY when attempting a
+    // non-blocking atomic commit. If we return false from here, that will cause
+    // the GPU process to CHECK itself. These are likely due to kernel bugs,
+    // which should be fixed, but rather than crashing we should retry the
+    // commit without the non-blocking flag and then it should work. This will
+    // cause a slight delay, but that should be imperceptible and better than
+    // crashing. We still do want the underlying driver bugs fixed, but this
+    // provide a better user experience.
+    flags &= ~DRM_MODE_ATOMIC_NONBLOCK;
+    result = drmModeAtomicCommit(file_.GetPlatformFile(), properties, flags,
+                                 reinterpret_cast<void*>(id));
+  }
+  if (!result) {
     if (page_flip_request) {
       page_flip_manager_->RegisterCallback(id, crtc_count,
                                            page_flip_request->AddPageFlip());
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 3089a822..dcea102 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -357,6 +357,10 @@
 
 void WaylandWindow::SizeConstraintsChanged() {}
 
+bool WaylandWindow::ShouldUseLayerForShapedWindow() const {
+  return true;
+}
+
 bool WaylandWindow::CanDispatchEvent(const PlatformEvent& event) {
   if (event->IsMouseEvent())
     return has_pointer_focus_;
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 45187098..be72605 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -157,6 +157,7 @@
   void SetWindowIcons(const gfx::ImageSkia& window_icon,
                       const gfx::ImageSkia& app_icon) override;
   void SizeConstraintsChanged() override;
+  bool ShouldUseLayerForShapedWindow() const override;
 
   // PlatformEventDispatcher
   bool CanDispatchEvent(const PlatformEvent& event) override;
diff --git a/ui/platform_window/platform_window.cc b/ui/platform_window/platform_window.cc
index 19b5fc5..0560e2e 100644
--- a/ui/platform_window/platform_window.cc
+++ b/ui/platform_window/platform_window.cc
@@ -54,4 +54,8 @@
   return std::string();
 }
 
+bool PlatformWindow::ShouldUseLayerForShapedWindow() const {
+  return false;
+}
+
 }  // namespace ui
diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h
index 0d9b0f9..b307b14 100644
--- a/ui/platform_window/platform_window.h
+++ b/ui/platform_window/platform_window.h
@@ -144,6 +144,10 @@
   // Returns a unique ID for the window. The interpretation of the ID is
   // platform specific. Overriding this method is optional.
   virtual std::string GetWindowUniqueId() const;
+
+  // Returns true if window shape should be updated in layer,
+  // otherwise false when platform window updates the window shape.
+  virtual bool ShouldUseLayerForShapedWindow() const;
 };
 
 }  // namespace ui
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 945ca33..6a1dc42a 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -1191,7 +1191,6 @@
     "window/dialog_delegate_unittest.cc",
     "window/frame_caption_button_unittest.cc",
     "window/hit_test_utils_unittest.cc",
-    "window/non_client_view_unittest.cc",
   ]
 
   configs += [ "//build/config:precompiled_headers" ]
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 58620fe..2a0f168 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -115,7 +115,8 @@
     ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
 
     widget_ = new Widget;
-    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+    Widget::InitParams params =
+        CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
     params.bounds = gfx::Rect(0, 0, 200, 200);
     widget_->Init(std::move(params));
 
@@ -127,7 +128,7 @@
     label_->SetID(DEFAULT_VIEW_ID);
     button_->AddChildView(label_);
 
-    widget_->GetContentsView()->AddChildView(button_);
+    widget_->GetRootView()->AddChildView(button_);
     widget_->Show();
   }
 
@@ -163,7 +164,7 @@
   // child Views.
   View::Views SetUpExtraViews() {
     View* parent_view =
-        widget_->GetContentsView()->AddChildView(std::make_unique<View>());
+        widget_->GetRootView()->AddChildView(std::make_unique<View>());
     View::Views views{parent_view};
     for (int i = 0; i < 4; i++)
       views.push_back(parent_view->AddChildView(std::make_unique<View>()));
@@ -223,7 +224,7 @@
     auto table =
         std::make_unique<TableView>(model_.get(), columns, TEXT_ONLY, true);
     table_ = table.get();
-    widget_->GetContentsView()->AddChildView(
+    widget_->GetRootView()->AddChildView(
         TableView::CreateScrollViewWithTable(std::move(table)));
   }
 
@@ -539,12 +540,12 @@
   ViewAXPlatformNodeDelegate* child_view_3 = view_accessibility(extra_views[3]);
   ViewAXPlatformNodeDelegate* child_view_4 = view_accessibility(extra_views[4]);
 
-  EXPECT_EQ(view_accessibility(widget_->GetContentsView())->GetNativeObject(),
+  EXPECT_EQ(view_accessibility(widget_->GetRootView())->GetNativeObject(),
             parent_view->GetParent());
   EXPECT_EQ(4, parent_view->GetChildCount());
 
-  EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
-  EXPECT_EQ(3, parent_view->GetIndexInParent());
+  EXPECT_EQ(0, button_accessibility()->GetIndexInParent());
+  EXPECT_EQ(1, parent_view->GetIndexInParent());
 
   EXPECT_EQ(child_view_1->GetNativeObject(), parent_view->ChildAtIndex(0));
   EXPECT_EQ(child_view_2->GetNativeObject(), parent_view->ChildAtIndex(1));
@@ -588,8 +589,6 @@
   // view is added as the next sibling of the already present button view.
   //
   // Widget
-  // ++NonClientView
-  // ++NonClientFrameView
   // ++Button
   // ++++Label
   // 0 = ++ParentView
@@ -599,7 +598,7 @@
   // 4 = ++++ChildView4
   View::Views extra_views = SetUpExtraViews();
   ViewAXPlatformNodeDelegate* contents_view =
-      view_accessibility(widget_->GetContentsView());
+      view_accessibility(widget_->GetRootView());
   ViewAXPlatformNodeDelegate* parent_view = view_accessibility(extra_views[0]);
   ViewAXPlatformNodeDelegate* child_view_1 = view_accessibility(extra_views[1]);
   ViewAXPlatformNodeDelegate* child_view_2 = view_accessibility(extra_views[2]);
@@ -613,12 +612,12 @@
   parent_view->OverrideIsLeaf(true);
   child_view_2->OverrideIsLeaf(true);
 
-  EXPECT_EQ(4, contents_view->GetChildCount());
+  EXPECT_EQ(2, contents_view->GetChildCount());
   EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
   EXPECT_EQ(0, parent_view->GetChildCount());
 
-  EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
-  EXPECT_EQ(3, parent_view->GetIndexInParent());
+  EXPECT_EQ(0, button_accessibility()->GetIndexInParent());
+  EXPECT_EQ(1, parent_view->GetIndexInParent());
 
   EXPECT_FALSE(contents_view->IsIgnored());
   EXPECT_FALSE(parent_view->IsIgnored());
@@ -650,12 +649,12 @@
   // have no effect.
   parent_view->OverrideIsLeaf(false);
 
-  EXPECT_EQ(4, contents_view->GetChildCount());
+  EXPECT_EQ(2, contents_view->GetChildCount());
   EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
   EXPECT_EQ(4, parent_view->GetChildCount());
 
-  EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
-  EXPECT_EQ(3, parent_view->GetIndexInParent());
+  EXPECT_EQ(0, button_accessibility()->GetIndexInParent());
+  EXPECT_EQ(1, parent_view->GetIndexInParent());
 
   EXPECT_FALSE(contents_view->IsIgnored());
   EXPECT_FALSE(parent_view->IsIgnored());
@@ -694,8 +693,6 @@
   // view is added as the next sibling of the already present button view.
   //
   // Widget
-  // ++NonClientView
-  // ++NonClientFrameView
   // ++Button
   // ++++Label
   // 0 = ++ParentView
@@ -705,7 +702,7 @@
   // 4 = ++++ChildView4
   View::Views extra_views = SetUpExtraViews();
   ViewAXPlatformNodeDelegate* contents_view =
-      view_accessibility(widget_->GetContentsView());
+      view_accessibility(widget_->GetRootView());
   ViewAXPlatformNodeDelegate* parent_view = view_accessibility(extra_views[0]);
   ViewAXPlatformNodeDelegate* child_view_1 = view_accessibility(extra_views[1]);
   ViewAXPlatformNodeDelegate* child_view_2 = view_accessibility(extra_views[2]);
@@ -719,7 +716,7 @@
   EXPECT_EQ(contents_view->GetNativeObject(), parent_view->GetParent());
   EXPECT_EQ(3, parent_view->GetChildCount());
 
-  EXPECT_EQ(2, button_accessibility()->GetIndexInParent());
+  EXPECT_EQ(0, button_accessibility()->GetIndexInParent());
   EXPECT_EQ(-1, parent_view->GetIndexInParent());
 
   EXPECT_EQ(child_view_1->GetNativeObject(), parent_view->ChildAtIndex(0));
@@ -727,17 +724,17 @@
   EXPECT_EQ(child_view_4->GetNativeObject(), parent_view->ChildAtIndex(2));
 
   EXPECT_EQ(button_accessibility()->GetNativeObject(),
-            contents_view->ChildAtIndex(2));
-  EXPECT_EQ(child_view_1->GetNativeObject(), contents_view->ChildAtIndex(3));
-  EXPECT_EQ(child_view_3->GetNativeObject(), contents_view->ChildAtIndex(4));
-  EXPECT_EQ(child_view_4->GetNativeObject(), contents_view->ChildAtIndex(5));
+            contents_view->ChildAtIndex(0));
+  EXPECT_EQ(child_view_1->GetNativeObject(), contents_view->ChildAtIndex(1));
+  EXPECT_EQ(child_view_3->GetNativeObject(), contents_view->ChildAtIndex(2));
+  EXPECT_EQ(child_view_4->GetNativeObject(), contents_view->ChildAtIndex(3));
 
   EXPECT_EQ(nullptr, parent_view->GetNextSibling());
   EXPECT_EQ(nullptr, parent_view->GetPreviousSibling());
 
   EXPECT_EQ(contents_view->GetNativeObject(), child_view_1->GetParent());
   EXPECT_EQ(0, child_view_1->GetChildCount());
-  EXPECT_EQ(3, child_view_1->GetIndexInParent());
+  EXPECT_EQ(1, child_view_1->GetIndexInParent());
   EXPECT_EQ(child_view_3->GetNativeObject(), child_view_1->GetNextSibling());
   EXPECT_EQ(button_accessibility()->GetNativeObject(),
             child_view_1->GetPreviousSibling());
@@ -750,14 +747,14 @@
 
   EXPECT_EQ(contents_view->GetNativeObject(), child_view_3->GetParent());
   EXPECT_EQ(0, child_view_3->GetChildCount());
-  EXPECT_EQ(4, child_view_3->GetIndexInParent());
+  EXPECT_EQ(2, child_view_3->GetIndexInParent());
   EXPECT_EQ(child_view_4->GetNativeObject(), child_view_3->GetNextSibling());
   EXPECT_EQ(child_view_1->GetNativeObject(),
             child_view_3->GetPreviousSibling());
 
   EXPECT_EQ(contents_view->GetNativeObject(), child_view_4->GetParent());
   EXPECT_EQ(0, child_view_4->GetChildCount());
-  EXPECT_EQ(5, child_view_4->GetIndexInParent());
+  EXPECT_EQ(3, child_view_4->GetIndexInParent());
   EXPECT_EQ(nullptr, child_view_4->GetNextSibling());
   EXPECT_EQ(child_view_3->GetNativeObject(),
             child_view_4->GetPreviousSibling());
diff --git a/ui/views/bubble/bubble_frame_view.cc b/ui/views/bubble/bubble_frame_view.cc
index 2c77698..9d92717 100644
--- a/ui/views/bubble/bubble_frame_view.cc
+++ b/ui/views/bubble/bubble_frame_view.cc
@@ -387,8 +387,20 @@
     header_bottom = header_view_->bounds().bottom();
   }
 
-  if (bounds.IsEmpty())
+  // Only account for footnote_container_'s height if it's visible, because
+  // content_margins_ adds extra padding even if all child views are invisible.
+  if (footnote_container_ && footnote_container_->GetVisible()) {
+    const int width = contents_bounds.width();
+    const int height = footnote_container_->GetHeightForWidth(width);
+    footnote_container_->SetBounds(
+        contents_bounds.x(), contents_bounds.bottom() - height, width, height);
+  }
+
+  NonClientFrameView::Layout();
+
+  if (bounds.IsEmpty()) {
     return;
+  }
 
   // The buttons are positioned somewhat closer to the edge of the bubble.
   const int close_margin =
@@ -438,15 +450,6 @@
 
   title_icon_->SetBounds(bounds.x(), bounds.y(), title_icon_pref_size.width(),
                          title_height);
-
-  // Only account for footnote_container_'s height if it's visible, because
-  // content_margins_ adds extra padding even if all child views are invisible.
-  if (footnote_container_ && footnote_container_->GetVisible()) {
-    const int width = contents_bounds.width();
-    const int height = footnote_container_->GetHeightForWidth(width);
-    footnote_container_->SetBounds(
-        contents_bounds.x(), contents_bounds.bottom() - height, width, height);
-  }
 }
 
 void BubbleFrameView::OnThemeChanged() {
diff --git a/ui/views/cocoa/drag_drop_client_mac_unittest.mm b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
index 92354bac..f30ff1e6 100644
--- a/ui/views/cocoa/drag_drop_client_mac_unittest.mm
+++ b/ui/views/cocoa/drag_drop_client_mac_unittest.mm
@@ -195,7 +195,7 @@
     widget_->Show();
 
     target_ = new DragDropView();
-    widget_->GetContentsView()->AddChildView(target_);
+    widget_->non_client_view()->frame_view()->AddChildView(target_);
     target_->SetBoundsRect(bounds);
 
     drag_drop_client()->source_operation_ = ui::DragDropTypes::DRAG_COPY;
@@ -329,7 +329,7 @@
   SetData(data);
 
   target_ = new DragDropCloseView();
-  widget_->GetContentsView()->AddChildView(target_);
+  widget_->non_client_view()->frame_view()->AddChildView(target_);
   target_->SetBoundsRect(gfx::Rect(0, 0, 100, 100));
   target_->set_formats(ui::OSExchangeData::STRING | ui::OSExchangeData::URL);
 
diff --git a/ui/views/controls/table/table_view_unittest.cc b/ui/views/controls/table/table_view_unittest.cc
index 7c5954e..fd13279 100644
--- a/ui/views/controls/table/table_view_unittest.cc
+++ b/ui/views/controls/table/table_view_unittest.cc
@@ -445,12 +445,13 @@
     helper_ = std::make_unique<TableViewTestHelper>(table_);
 
     widget_ = std::make_unique<Widget>();
-    Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_WINDOW);
+    Widget::InitParams params =
+        CreateParams(Widget::InitParams::TYPE_WINDOW_FRAMELESS);
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.bounds = gfx::Rect(0, 0, 650, 650);
     params.delegate = GetWidgetDelegate(widget_.get());
     widget_->Init(std::move(params));
-    widget_->GetContentsView()->AddChildView(std::move(scroll_view));
+    widget_->GetRootView()->AddChildView(std::move(scroll_view));
     widget_->Show();
   }
 
diff --git a/ui/views/view_unittest_mac.mm b/ui/views/view_unittest_mac.mm
index f2e372418..a3f5c3e2 100644
--- a/ui/views/view_unittest_mac.mm
+++ b/ui/views/view_unittest_mac.mm
@@ -117,7 +117,7 @@
 
     view_ = new ThreeFingerSwipeView;
     view_->SetSize(widget_->GetClientAreaBoundsInScreen().size());
-    widget_->GetContentsView()->AddChildView(view_);
+    widget_->non_client_view()->frame_view()->AddChildView(view_);
   }
 
   void TearDown() override {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 287d8b4..ea22d84 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -584,9 +584,7 @@
 
 bool DesktopWindowTreeHostPlatform::ShouldWindowContentsBeTransparent() const {
   return platform_window()->ShouldWindowContentsBeTransparent() ||
-         !const_cast<DesktopWindowTreeHostPlatform*>(this)
-              ->GetWindowMaskForWindowShapeInPixels()
-              .isEmpty();
+         ShouldUseLayerForShapedWindow();
 }
 
 void DesktopWindowTreeHostPlatform::FrameTypeChanged() {
@@ -831,7 +829,7 @@
     ui::PlatformWindowInitProperties* properties) {}
 
 bool DesktopWindowTreeHostPlatform::ShouldUseLayerForShapedWindow() const {
-  return true;
+  return platform_window()->ShouldUseLayerForShapedWindow();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
index 4223f40..6d431251 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform_unittest.cc
@@ -12,6 +12,7 @@
 #include "ui/aura/window_tree_host.h"
 #include "ui/aura/window_tree_host_observer.h"
 #include "ui/display/display_switches.h"
+#include "ui/platform_window/platform_window.h"
 #include "ui/views/test/views_test_base.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 #include "ui/views/widget/widget_observer.h"
@@ -178,6 +179,9 @@
   auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
       widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
   ASSERT_TRUE(host_platform);
+  if (!host_platform->platform_window()->ShouldUseLayerForShapedWindow())
+    return;
+
   auto* content_window =
       DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
           widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
@@ -306,6 +310,9 @@
   auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
       widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
   ASSERT_TRUE(host_platform);
+  if (!host_platform->platform_window()->ShouldUseLayerForShapedWindow())
+    return;
+
   auto* content_window =
       DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
           widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index 4fbd83a..80234d5 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -573,8 +573,10 @@
 
   Widget* widget = CreateTopLevelPlatformWidget();
   widget->SetBounds(gfx::Rect(0, 0, 300, 300));
-  widget->GetContentsView()->AddChildView(new CursorView(0, hand));
-  widget->GetContentsView()->AddChildView(new CursorView(100, ibeam));
+  widget->non_client_view()->frame_view()->AddChildView(
+      new CursorView(0, hand));
+  widget->non_client_view()->frame_view()->AddChildView(
+      new CursorView(100, ibeam));
   widget->Show();
   NSWindow* widget_window = widget->GetNativeWindow().GetNativeNSWindow();
 
@@ -877,8 +879,8 @@
   const std::u16string long_tooltip(2000, 'W');
 
   // Create a nested layout to test corner cases.
-  LabelButton* back =
-      widget->GetContentsView()->AddChildView(std::make_unique<LabelButton>());
+  LabelButton* back = widget->non_client_view()->frame_view()->AddChildView(
+      std::make_unique<LabelButton>());
   back->SetBounds(10, 10, 80, 80);
   widget->Show();
 
@@ -943,7 +945,7 @@
   CustomTooltipView* view_below =
       new CustomTooltipView(base::ASCIIToUTF16("Back"), view_above);
   view_below->SetBoundsRect(widget_below->GetContentsView()->bounds());
-  widget_below->GetContentsView()->AddChildView(view_below);
+  widget_below->non_client_view()->frame_view()->AddChildView(view_below);
 
   widget_below->Show();
   widget_above->Show();
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 955dae8..3067a339 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -3773,7 +3773,7 @@
   WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
   widget->SetBounds(gfx::Rect(0, 0, 600, 600));
   EventCountView* event_count_view = new EventCountView();
-  widget->GetContentsView()->AddChildView(event_count_view);
+  widget->client_view()->AddChildView(event_count_view);
   event_count_view->SetBounds(0, 0, 600, 600);
   widget->Show();
 
@@ -3784,81 +3784,6 @@
   EXPECT_EQ(1, event_count_view->GetEventCount(ui::ET_MOUSEWHEEL));
 }
 
-class LayoutCountingView : public View {
- public:
-  LayoutCountingView() = default;
-  ~LayoutCountingView() override = default;
-
-  void set_layout_closure(base::OnceClosure layout_closure) {
-    layout_closure_ = std::move(layout_closure);
-  }
-
-  size_t GetAndClearLayoutCount() {
-    const size_t count = layout_count_;
-    layout_count_ = 0u;
-    return count;
-  }
-
-  // View:
-  void Layout() override {
-    ++layout_count_;
-    View::Layout();
-    if (layout_closure_)
-      std::move(layout_closure_).Run();
-  }
-
- private:
-  size_t layout_count_ = 0u;
-
-  // If valid, this is run when Layout() is called.
-  base::OnceClosure layout_closure_;
-
-  DISALLOW_COPY_AND_ASSIGN(LayoutCountingView);
-};
-
-using WidgetInvalidateLayoutTest = ViewsTestBaseWithNativeWidgetType;
-
-TEST_P(WidgetInvalidateLayoutTest, InvalidateLayout) {
-  std::unique_ptr<Widget> widget =
-      CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
-  LayoutCountingView* view =
-      widget->widget_delegate()->GetContentsView()->AddChildView(
-          std::make_unique<LayoutCountingView>());
-  view->parent()->SetLayoutManager(std::make_unique<FillLayout>());
-  // Force an initial Layout().
-  // TODO(sky): this shouldn't be necessary, adding a child view should trigger
-  // ScheduleLayout().
-  view->Layout();
-  widget->Show();
-
-  ui::Compositor* compositor = widget->GetCompositor();
-  ASSERT_TRUE(compositor);
-  compositor->ScheduleDraw();
-  ui::DrawWaiterForTest::WaitForCompositingEnded(compositor);
-
-  base::RunLoop run_loop;
-  view->GetAndClearLayoutCount();
-  // Don't use WaitForCompositingEnded() here as it's entirely possible nothing
-  // will be drawn (which means WaitForCompositingEnded() isn't run). Instead
-  // wait for Layout() to be called.
-  view->set_layout_closure(run_loop.QuitClosure());
-  EXPECT_FALSE(ViewTestApi(view).needs_layout());
-  EXPECT_FALSE(ViewTestApi(widget->GetRootView()).needs_layout());
-  view->InvalidateLayout();
-  EXPECT_TRUE(ViewTestApi(view).needs_layout());
-  EXPECT_TRUE(ViewTestApi(widget->GetRootView()).needs_layout());
-  run_loop.Run();
-  EXPECT_EQ(1u, view->GetAndClearLayoutCount());
-  EXPECT_FALSE(ViewTestApi(view).needs_layout());
-  EXPECT_FALSE(ViewTestApi(widget->GetRootView()).needs_layout());
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    WidgetInvalidateLayoutTest,
-    WidgetInvalidateLayoutTest,
-    ::testing::Values(ViewsTestBase::NativeWidgetType::kDefault,
-                      ViewsTestBase::NativeWidgetType::kDesktop));
-
 class WidgetShadowTest : public WidgetTest {
  public:
   WidgetShadowTest() = default;
diff --git a/ui/views/window/client_view.cc b/ui/views/window/client_view.cc
index 5527e26..227efb2 100644
--- a/ui/views/window/client_view.cc
+++ b/ui/views/window/client_view.cc
@@ -87,8 +87,6 @@
     // TODO(weili): This seems fragile and can be refactored.
     // Tracked at https://crbug.com/1012466.
     AddChildViewAt(contents_view_, 0);
-  } else if (!details.is_add && details.child == contents_view_) {
-    contents_view_ = nullptr;
   }
 }
 
diff --git a/ui/views/window/custom_frame_view.cc b/ui/views/window/custom_frame_view.cc
index eda68f6..9c2f931 100644
--- a/ui/views/window/custom_frame_view.cc
+++ b/ui/views/window/custom_frame_view.cc
@@ -211,6 +211,7 @@
   }
 
   LayoutClientView();
+  NonClientFrameView::Layout();
 }
 
 gfx::Size CustomFrameView::CalculatePreferredSize() const {
diff --git a/ui/views/window/non_client_view.cc b/ui/views/window/non_client_view.cc
index 73170394..9511645 100644
--- a/ui/views/window/non_client_view.cc
+++ b/ui/views/window/non_client_view.cc
@@ -11,6 +11,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/hit_test.h"
 #include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/views/layout/fill_layout.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 #include "ui/views/rect_based_targeting_utils.h"
 #include "ui/views/view_targeter.h"
@@ -24,18 +25,6 @@
 
 namespace views {
 
-namespace {
-
-// The frame view and the client view are always at these specific indices,
-// because the RootView message dispatch sends messages to items higher in the
-// z-order first and we always want the client view to have first crack at
-// handling mouse messages.
-constexpr int kFrameViewIndex = 0;
-constexpr int kClientViewIndex = 1;
-// The overlay view is always on top (view == children().back()).
-
-}  // namespace
-
 NonClientFrameView::~NonClientFrameView() = default;
 
 bool NonClientFrameView::ShouldPaintAsActive() const {
@@ -129,18 +118,17 @@
   SchedulePaint();
 }
 
-NonClientFrameView::NonClientFrameView() {
-  SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
+void NonClientFrameView::Layout() {
+  views::ClientView* client_view = GetWidget()->client_view();
+  client_view->SetBoundsRect(GetBoundsForClientView());
+  SkPath client_clip;
+  if (GetClientMask(client_view->size(), &client_clip))
+    client_view->SetClipPath(client_clip);
+  views::View::Layout();
 }
 
-// ViewTargeterDelegate:
-bool NonClientFrameView::DoesIntersectRect(const View* target,
-                                           const gfx::Rect& rect) const {
-  CHECK_EQ(target, this);
-
-  // For the default case, we assume the non-client frame view never overlaps
-  // the client view.
-  return !GetWidget()->client_view()->bounds().Intersects(rect);
+NonClientFrameView::NonClientFrameView() {
+  SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
 }
 
 #if defined(OS_WIN)
@@ -165,13 +153,18 @@
 
 void NonClientView::SetFrameView(
     std::unique_ptr<NonClientFrameView> frame_view) {
-  // See comment in header about ownership.
-  frame_view->set_owned_by_client();
-  if (frame_view_.get())
+  // If there is an existing frame view, remove the client view before removing
+  // the frame view to prevent the client view from being deleted.
+  if (frame_view_.get()) {
+    frame_view_->RemoveChildView(client_view_);
     RemoveChildView(frame_view_.get());
+  }
+
   frame_view_ = std::move(frame_view);
-  if (parent())
-    AddChildViewAt(frame_view_.get(), kFrameViewIndex);
+  if (parent()) {
+    AddChildViewAt(frame_view_.get(), 0);
+    frame_view_->AddChildViewAt(client_view_, 0);
+  }
 }
 
 void NonClientView::SetOverlayView(View* view) {
@@ -262,11 +255,6 @@
   // into a View hierarchy once" ( http://codereview.chromium.org/27317 ), but
   // where that is still the case it should simply be fixed.
   frame_view_->SetBoundsRect(GetLocalBounds());
-  client_view_->SetBoundsRect(frame_view_->GetBoundsForClientView());
-
-  SkPath client_clip;
-  if (frame_view_->GetClientMask(client_view_->size(), &client_clip))
-    client_view_->SetClipPath(client_clip);
 
   if (overlay_view_)
     overlay_view_->SetBoundsRect(GetLocalBounds());
@@ -302,8 +290,8 @@
   // the various setters, and create and add children directly in the
   // constructor.
   if (details.is_add && GetWidget() && details.child == this) {
-    AddChildViewAt(frame_view_.get(), kFrameViewIndex);
-    AddChildViewAt(client_view_, kClientViewIndex);
+    AddChildViewAt(frame_view_.get(), 0);
+    frame_view_->AddChildViewAt(client_view_, 0);
     if (overlay_view_)
       AddChildView(overlay_view_);
   }
diff --git a/ui/views/window/non_client_view.h b/ui/views/window/non_client_view.h
index 58558cc..c47c5b63 100644
--- a/ui/views/window/non_client_view.h
+++ b/ui/views/window/non_client_view.h
@@ -101,11 +101,7 @@
   // View:
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void OnThemeChanged() override;
-
- protected:
-  // ViewTargeterDelegate:
-  bool DoesIntersectRect(const View* target,
-                         const gfx::Rect& rect) const override;
+  void Layout() override;
 
  private:
 #if defined(OS_WIN)
@@ -121,10 +117,11 @@
 //
 //  The NonClientView is the logical root of all Views contained within a
 //  Window, except for the RootView which is its parent and of which it is the
-//  sole child. The NonClientView has two children, the NonClientFrameView which
+//  sole child. The NonClientView has one child, the NonClientFrameView which
 //  is responsible for painting and responding to events from the non-client
-//  portions of the window, and the ClientView, which is responsible for the
-//  same for the client area of the window:
+//  portions of the window, and for forwarding events to its child, the
+//  ClientView, which is responsible for the same for the client area of the
+//  window:
 //
 //  +- views::Widget ------------------------------------+
 //  | +- views::RootView ------------------------------+ |
@@ -135,23 +132,17 @@
 //  | | | | << of the non-client areas of a     >> | | | |
 //  | | | | << views::Widget.                   >> | | | |
 //  | | | |                                        | | | |
-//  | | | +----------------------------------------+ | | |
-//  | | | +- views::ClientView or subclass --------+ | | |
-//  | | | |                                        | | | |
-//  | | | | << all painting and event receiving >> | | | |
-//  | | | | << of the client areas of a         >> | | | |
-//  | | | | << views::Widget.                   >> | | | |
-//  | | | |                                        | | | |
+//  | | | | +- views::ClientView or subclass ----+ | | | |
+//  | | | | |                                    | | | | |
+//  | | | | | << all painting and event       >> | | | | |
+//  | | | | | << receiving of the client      >> | | | | |
+//  | | | | | << areas of a views::Widget.    >> | | | | |
+//  | | | | +----------------------------------+ | | | | |
 //  | | | +----------------------------------------+ | | |
 //  | | +--------------------------------------------+ | |
 //  | +------------------------------------------------+ |
 //  +----------------------------------------------------+
 //
-// The NonClientFrameView and ClientView are siblings because due to theme
-// changes the NonClientFrameView may be replaced with different
-// implementations (e.g. during the switch from DWM/Aero-Glass to Vista Basic/
-// Classic rendering).
-//
 class VIEWS_EXPORT NonClientView : public View, public ViewTargeterDelegate {
  public:
   METADATA_HEADER(NonClientView);
diff --git a/ui/views/window/non_client_view_unittest.cc b/ui/views/window/non_client_view_unittest.cc
deleted file mode 100644
index fd66cb2..0000000
--- a/ui/views/window/non_client_view_unittest.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2018 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 "ui/views/window/non_client_view.h"
-
-#include <memory>
-
-#include "ui/views/test/views_test_base.h"
-#include "ui/views/widget/widget_delegate.h"
-#include "ui/views/window/client_view.h"
-#include "ui/views/window/native_frame_view.h"
-
-namespace views {
-namespace test {
-
-namespace {
-
-class NonClientFrameTestView : public NativeFrameView {
- public:
-  using NativeFrameView::NativeFrameView;
-  int layout_count() const { return layout_count_; }
-
-  // NativeFrameView:
-  void Layout() override {
-    NativeFrameView::Layout();
-    ++layout_count_;
-  }
-
- private:
-  int layout_count_ = 0;
-};
-
-class ClientTestView : public ClientView {
- public:
-  using ClientView::ClientView;
-  int layout_count() const { return layout_count_; }
-
-  // ClientView:
-  void Layout() override {
-    ClientView::Layout();
-    ++layout_count_;
-  }
-
- private:
-  int layout_count_ = 0;
-};
-
-class TestWidgetDelegate : public WidgetDelegateView {
- public:
-  // WidgetDelegateView:
-  std::unique_ptr<NonClientFrameView> CreateNonClientFrameView(
-      Widget* widget) override {
-    return std::make_unique<NonClientFrameTestView>(widget);
-  }
-
-  views::ClientView* CreateClientView(Widget* widget) override {
-    return new ClientTestView(widget, this);
-  }
-};
-
-class NonClientViewTest : public ViewsTestBase {
- public:
-  Widget::InitParams CreateParams(Widget::InitParams::Type type) override {
-    Widget::InitParams params = ViewsTestBase::CreateParams(type);
-    params.delegate = new TestWidgetDelegate;
-    return params;
-  }
-};
-
-}  // namespace
-
-// Ensure Layout() is not called excessively on a ClientView when Widget bounds
-// are changing.
-TEST_F(NonClientViewTest, OnlyLayoutChildViewsOnce) {
-  std::unique_ptr<views::Widget> widget =
-      CreateTestWidget(Widget::InitParams::TYPE_WINDOW);
-
-  NonClientView* non_client_view = widget->non_client_view();
-  non_client_view->Layout();
-
-  auto* frame_view =
-      static_cast<NonClientFrameTestView*>(non_client_view->frame_view());
-  auto* client_view =
-      static_cast<ClientTestView*>(non_client_view->client_view());
-
-  int initial_frame_view_layouts = frame_view->layout_count();
-  int initial_client_view_layouts = client_view->layout_count();
-
-  // Make sure it does no layout when nothing has changed.
-  non_client_view->Layout();
-  EXPECT_EQ(frame_view->layout_count(), initial_frame_view_layouts);
-  EXPECT_EQ(client_view->layout_count(), initial_client_view_layouts);
-
-  // Ensure changing bounds triggers a (single) layout.
-  widget->SetBounds(gfx::Rect(0, 0, 161, 100));
-  EXPECT_EQ(frame_view->layout_count(), initial_frame_view_layouts + 1);
-  EXPECT_EQ(client_view->layout_count(), initial_client_view_layouts + 1);
-}
-
-}  // namespace test
-}  // namespace views
diff --git a/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
index 86a0df9..b844d10 100644
--- a/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
+++ b/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js
@@ -70,6 +70,22 @@
     },
 
     /**
+     * Enum used as an ID for specific UI elements.
+     * A UiElement is passed between html and JS for
+     * certain UI elements to determine their state.
+     *
+     * @type {!UiElement}
+     */
+    UiElement: {
+      type: Object,
+      value: UiElement,
+    },
+
+    showNoProfilesMessage: {
+      type: Boolean,
+    },
+
+    /**
      * @type {!PageState}
      * @private
      */
@@ -87,21 +103,14 @@
     },
 
     /**
-     * Enum used as an ID for specific UI elements.
-     * A UiElement is passed between html and JS for
-     * certain UI elements to determine their state.
-     *
-     * @type {!UiElement}
+     *  TODO(crbug.com/1093185): add type |BarcodeDetector| when externs
+     *  becomes available
+     *  @private {?Object}
      */
-    UiElement: {
+    qrCodeDetector_: {
       type: Object,
-      value: UiElement,
+      value: null,
     },
-
-    /** @private */
-    showNoProfilesMessage: {
-      type: Boolean,
-    }
   },
 
   /**
@@ -122,12 +131,6 @@
    */
   qrCodeDetectorTimer_: null,
 
-  /**
-   *  TODO(crbug.com/1093185): add type |BarcodeDetector| when externs
-   *  becomes available
-   *  @private
-   */
-  qrCodeDetector_: null,
 
   /**
    * The function used to initiate a repeating timer. Can be overwritten in
@@ -169,7 +172,7 @@
   /** @override */
   ready() {
     this.setMediaDevices(navigator.mediaDevices);
-    this.initBarcodeDetector();
+    this.initBarcodeDetector_();
     this.state_ = PageState.MANUAL_ENTRY;
   },
 
@@ -197,7 +200,7 @@
    * @suppress {undefinedVars|missingProperties}
    * @private
    */
-  async initBarcodeDetector() {
+  async initBarcodeDetector_() {
     const formats = await this.barcodeDetectorClass_.getSupportedFormats();
 
     if (!formats || formats.length === 0) {
@@ -229,11 +232,11 @@
    * @param {function()} playVideoFunction
    * @param {function(MediaStream)} stopStreamFunction
    */
-  setFakesForTesting(
+  async setFakesForTesting(
       barcodeDetectorClass, imageCaptureClass, setIntervalFunction,
       playVideoFunction, stopStreamFunction) {
     this.barcodeDetectorClass_ = barcodeDetectorClass;
-    this.initBarcodeDetector();
+    await this.initBarcodeDetector_();
     this.imageCaptureClass_ = imageCaptureClass;
     this.setIntervalFunction_ = setIntervalFunction;
     this.playVideo_ = playVideoFunction;
diff --git a/ui/webui/resources/cr_components/chromeos/network/network_config.js b/ui/webui/resources/cr_components/chromeos/network/network_config.js
index 59dbbd4..77ba92e 100644
--- a/ui/webui/resources/cr_components/chromeos/network/network_config.js
+++ b/ui/webui/resources/cr_components/chromeos/network/network_config.js
@@ -661,11 +661,13 @@
       return;
     }
     if (this.shareAllowEnable) {
-      // New insecure WiFi networks are always shared.
-      if (this.mojoType_ === mojom.NetworkType.kWiFi &&
-          this.managedProperties_.typeProperties.wifi.security ===
-              mojom.SecurityType.kNone) {
-        this.shareNetwork_ = true;
+      // By default, Wi-Fi networks which require passwords are not shared,
+      // but "insecure" networks with no passwords are shared. In either case,
+      // the user can change the sharing setting by updating the toggle in the
+      // UI.
+
+      if (this.mojoType_ === mojom.NetworkType.kWiFi) {
+        this.shareNetwork_ = this.securityType_ === mojom.SecurityType.kNone;
         return;
       }
     }
diff --git a/weblayer/browser/background_fetch/background_fetch_delegate_impl.cc b/weblayer/browser/background_fetch/background_fetch_delegate_impl.cc
index 1000064..7b5fd43 100644
--- a/weblayer/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/weblayer/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -223,6 +223,22 @@
   }
 }
 
+void BackgroundFetchDelegateImpl::OnUiFinished(const std::string& job_id,
+                                               bool activated) {
+  auto job_details_iter = job_details_map_.find(job_id);
+  DCHECK(job_details_iter != job_details_map_.end());
+
+  if (activated) {
+    JobDetails& job_details = job_details_iter->second;
+    DCHECK_EQ(JobDetails::State::kJobComplete, job_details.job_state);
+
+    job_details.client->OnUIActivated(job_id);
+  }
+
+  job_details_map_.erase(job_details_iter);
+  ui_item_map_.erase(job_id);
+}
+
 void BackgroundFetchDelegateImpl::OnJobCreated(const std::string& job_id,
                                                const JobDetails* job) {
   ui_item_map_.emplace(std::piecewise_construct, std::forward_as_tuple(job_id),
@@ -231,11 +247,12 @@
 
 void BackgroundFetchDelegateImpl::UpdateUiAndUpdateObservers(
     const std::string& job_id) {
-  DCHECK(ui_item_map_.count(job_id));
-  BackgroundFetchDownload* download = &ui_item_map_.find(job_id)->second;
+  auto iter = ui_item_map_.find(job_id);
+  if (iter == ui_item_map_.end())
+    return;
 
-  // Do nothing if it has not yet been added to the UI. For example, if it's
-  // aborted before the download starts.
+  BackgroundFetchDownload* download = &iter->second;
+
   if (!download->HasBeenAddedToUi())
     return;
 
@@ -280,12 +297,27 @@
   auto job_details_iter = job_details_map_.find(job_id);
   DCHECK(job_details_iter != job_details_map_.end());
 
+  if (job_details_iter->second.job_state == JobDetails::State::kCancelled) {
+    OnUiFinished(job_id, /*activated=*/false);
+    return;
+  }
+
   JobDetails& job_details = job_details_iter->second;
   job_details.job_state = JobDetails::State::kJobComplete;
 
   // Clear the |job_details| internals that are no longer needed.
   job_details.current_fetch_guids.clear();
-  job_details.fetch_description.reset();
+
+  // The UI should have already been updated to the Completed state, however,
+  // sometimes Android drops notification updates if there have been too many
+  // requested in a short span of time, so make sure the completed state is
+  // reflected in the UI after a brief delay. See
+  // https://developer.android.com/training/notify-user/build-notification#Updating
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&BackgroundFetchDelegateImpl::UpdateUiAndUpdateObservers,
+                     weak_ptr_factory_.GetWeakPtr(), job_id),
+      base::TimeDelta::FromMilliseconds(1500));
 }
 
 void BackgroundFetchDelegateImpl::UpdateUI(
diff --git a/weblayer/browser/background_fetch/background_fetch_delegate_impl.h b/weblayer/browser/background_fetch/background_fetch_delegate_impl.h
index ac0f06ee..1d0fda1 100644
--- a/weblayer/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/weblayer/browser/background_fetch/background_fetch_delegate_impl.h
@@ -111,6 +111,10 @@
   void ResumeDownload(const std::string& job_id);
   void CancelDownload(const std::string& job_id);
 
+  // Called when the UI has finished showing. If |activated| is true, it was
+  // tapped, otherwise it was dismissed.
+  void OnUiFinished(const std::string& job_id, bool activated);
+
   // TODO(estade): make these override virtual methods from a base class that's
   // shared with Chrome.
   void OnJobCreated(const std::string& job_id, const JobDetails* job);
@@ -145,11 +149,9 @@
   std::map<std::string, std::string> download_job_id_map_;
 
   // Map from job unique ids to the details of the job.
-  // TODO(estade): this map needs to have its items erased at some point.
   std::map<std::string, JobDetails> job_details_map_;
 
   // Map from job unique ids to the UI item for the job.
-  // TODO(estade): this map needs to have its items erased at some point.
   std::map<std::string, BackgroundFetchDownload> ui_item_map_;
 
   std::unique_ptr<download::DownloadService> download_service_;
diff --git a/weblayer/browser/background_fetch/background_fetch_download.cc b/weblayer/browser/background_fetch/background_fetch_download.cc
index c4ef437..513c3c67 100644
--- a/weblayer/browser/background_fetch/background_fetch_download.cc
+++ b/weblayer/browser/background_fetch/background_fetch_download.cc
@@ -101,4 +101,9 @@
   return &job_->fetch_description->icon;
 }
 
+void BackgroundFetchDownload::OnFinished(bool activated) {
+  controller_->OnUiFinished(job_id_, activated);
+  // |this| is deleted.
+}
+
 }  // namespace weblayer
diff --git a/weblayer/browser/background_fetch/background_fetch_download.h b/weblayer/browser/background_fetch/background_fetch_download.h
index 6fc7506..1e14d0100 100644
--- a/weblayer/browser/background_fetch/background_fetch_download.h
+++ b/weblayer/browser/background_fetch/background_fetch_download.h
@@ -42,6 +42,7 @@
   bool IsTransient() override;
   GURL GetSourceUrl() override;
   const SkBitmap* GetLargeIcon() override;
+  void OnFinished(bool activated) override;
 
  private:
   BackgroundFetchDelegateImpl* controller_;
diff --git a/weblayer/browser/download_impl.h b/weblayer/browser/download_impl.h
index ca92f08..6b7ae60 100644
--- a/weblayer/browser/download_impl.h
+++ b/weblayer/browser/download_impl.h
@@ -37,6 +37,9 @@
   void PauseImpl(JNIEnv* env) { Pause(); }
   void ResumeImpl(JNIEnv* env) { Resume(); }
   void CancelImpl(JNIEnv* env) { Cancel(); }
+  void OnFinishedImpl(JNIEnv* env, jboolean activated) {
+    OnFinished(activated);
+  }
   base::android::ScopedJavaLocalRef<jstring> GetLocationImpl(JNIEnv* env);
   base::android::ScopedJavaLocalRef<jstring> GetFileNameToReportToUserImpl(
       JNIEnv* env);
@@ -64,6 +67,10 @@
   // icon will be displayed.
   virtual const SkBitmap* GetLargeIcon() = 0;
 
+  // Called when the UI is gone. |activated| is true if the UI was activated, or
+  // false if it was simply dismissed.
+  virtual void OnFinished(bool activated) = 0;
+
   // Returns whether this download has been added to the UI via
   // DownloadDelegate::OnDownloadStarted.
   bool HasBeenAddedToUi();
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
index 7bcb103..56bae6e 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/DownloadImpl.java
@@ -4,6 +4,7 @@
 
 package org.chromium.weblayer_private;
 
+import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -48,6 +49,8 @@
 
     // These actions have to be synchronized with the receiver defined in AndroidManifest.xml.
     private static final String OPEN_INTENT = DOWNLOADS_PREFIX + ".OPEN";
+    private static final String ACTIVATE_TRANSIENT_INTENT =
+            DOWNLOADS_PREFIX + ".ACTIVATE_TRANSIENT";
     private static final String DELETE_INTENT = DOWNLOADS_PREFIX + ".DELETE";
     private static final String PAUSE_INTENT = DOWNLOADS_PREFIX + ".PAUSE";
     private static final String RESUME_INTENT = DOWNLOADS_PREFIX + ".RESUME";
@@ -62,6 +65,8 @@
             DOWNLOADS_PREFIX + ".NOTIFICATION_PROFILE";
     private static final String EXTRA_NOTIFICATION_PROFILE_IS_INCOGNITO =
             DOWNLOADS_PREFIX + ".NOTIFICATION_PROFILE_IS_INCOGNITO";
+    private static final String EXTRA_NOTIFICATION_SESSION_ID =
+            DOWNLOADS_PREFIX + ".NOTIFICATION_SESSION_ID";
     // The intent prefix is used as the notification's tag since it's guaranteed not to conflict
     // with intent prefixes used by other subsystems that display notifications.
     private static final String NOTIFICATION_TAG = DOWNLOADS_PREFIX;
@@ -160,6 +165,10 @@
             download.cancel();
         } else if (intent.getAction().equals(DELETE_INTENT)) {
             sMap.remove(id);
+            DownloadImplJni.get().onFinishedImpl(download.mNativeDownloadImpl, /*activated=*/false);
+        } else if (intent.getAction().equals(ACTIVATE_TRANSIENT_INTENT)) {
+            assert download.mIsTransient;
+            DownloadImplJni.get().onFinishedImpl(download.mNativeDownloadImpl, /*activated=*/true);
         }
     }
 
@@ -364,8 +373,7 @@
         Context context = ContextUtils.getApplicationContext();
 
         Intent deleteIntent = createIntent(DELETE_INTENT);
-        PendingIntentProvider deletePendingIntent =
-                PendingIntentProvider.getBroadcast(context, mNotificationId, deleteIntent, 0);
+        PendingIntentProvider deletePendingIntent = getPendingIntentProvider(deleteIntent);
 
         @DownloadState
         int state = getState();
@@ -417,24 +425,22 @@
                     .setAutoCancel(true)
                     .setProgress(0, 0, false);
 
+            Intent openIntent = null;
+
             if (mIsTransient) {
                 builder.setContentText(
                         resources.getString(R.string.download_notification_completed));
-                // TODO(estade): for transient downloads, create an intent that delegates back to
-                // native code.
+                openIntent = createIntent(ACTIVATE_TRANSIENT_INTENT);
             } else {
                 builder.setContentText(
                         resources.getString(R.string.download_notification_completed_with_size,
                                 DownloadUtils.getStringForBytes(context, getTotalBytes())));
 
-                Intent openIntent = createIntent(OPEN_INTENT);
+                openIntent = createIntent(OPEN_INTENT);
                 openIntent.putExtra(EXTRA_NOTIFICATION_LOCATION, getLocation());
                 openIntent.putExtra(EXTRA_NOTIFICATION_MIME_TYPE, getMimeType());
-                PendingIntentProvider openPendingIntent =
-                        PendingIntentProvider.getBroadcast(context, mNotificationId, openIntent, 0);
-
-                builder.setContentIntent(openPendingIntent);
             }
+            builder.setContentIntent(getPendingIntentProvider(openIntent));
         } else if (state == DownloadState.FAILED) {
             builder.setContentText(resources.getString(R.string.download_notification_failed))
                     .setOngoing(false)
@@ -442,8 +448,7 @@
                     .setProgress(0, 0, false);
         } else if (state == DownloadState.IN_PROGRESS) {
             Intent pauseIntent = createIntent(PAUSE_INTENT);
-            PendingIntentProvider pausePendingIntent =
-                    PendingIntentProvider.getBroadcast(context, mNotificationId, pauseIntent, 0);
+            PendingIntentProvider pausePendingIntent = getPendingIntentProvider(pauseIntent);
 
             long bytes = getReceivedBytes();
             long totalBytes = getTotalBytes();
@@ -453,26 +458,27 @@
                 progressCurrent = (int) (bytes * 100 / totalBytes);
             }
 
-            String contentText;
-            String bytesString = DownloadUtils.getStringForBytes(context, bytes);
-            if (indeterminate) {
-                contentText =
-                        resources.getString(R.string.download_ui_indeterminate_bytes, bytesString);
-            } else {
-                String totalString = DownloadUtils.getStringForBytes(context, totalBytes);
-                contentText = resources.getString(
-                        R.string.download_ui_determinate_bytes, bytesString, totalString);
+            if (!mIsTransient) {
+                String contentText;
+                String bytesString = DownloadUtils.getStringForBytes(context, bytes);
+                if (indeterminate) {
+                    contentText = resources.getString(
+                            R.string.download_ui_indeterminate_bytes, bytesString);
+                } else {
+                    String totalString = DownloadUtils.getStringForBytes(context, totalBytes);
+                    contentText = resources.getString(
+                            R.string.download_ui_determinate_bytes, bytesString, totalString);
+                }
+                builder.setContentText(contentText);
             }
-            builder.setContentText(contentText)
-                    .addAction(0 /* no icon */,
-                            resources.getString(R.string.download_notification_pause_button),
-                            pausePendingIntent, 0 /* no action for UMA */)
+            builder.addAction(0 /* no icon */,
+                           resources.getString(R.string.download_notification_pause_button),
+                           pausePendingIntent, 0 /* no action for UMA */)
                     .setSmallIcon(android.R.drawable.stat_sys_download)
                     .setProgress(100, progressCurrent, indeterminate);
         } else if (state == DownloadState.PAUSED) {
             Intent resumeIntent = createIntent(RESUME_INTENT);
-            PendingIntentProvider resumePendingIntent =
-                    PendingIntentProvider.getBroadcast(context, mNotificationId, resumeIntent, 0);
+            PendingIntentProvider resumePendingIntent = getPendingIntentProvider(resumeIntent);
             builder.setContentText(resources.getString(R.string.download_notification_paused))
                     .addAction(0 /* no icon */,
                             resources.getString(R.string.download_notification_resume_button),
@@ -483,8 +489,7 @@
 
         if (state == DownloadState.IN_PROGRESS || state == DownloadState.PAUSED) {
             Intent cancelIntent = createIntent(CANCEL_INTENT);
-            PendingIntentProvider cancelPendingIntent =
-                    PendingIntentProvider.getBroadcast(context, mNotificationId, cancelIntent, 0);
+            PendingIntentProvider cancelPendingIntent = getPendingIntentProvider(cancelIntent);
             builder.addAction(0 /* no icon */,
                     resources.getString(R.string.download_notification_cancel_button),
                     cancelPendingIntent, 0 /* no action for UMA */);
@@ -493,6 +498,16 @@
         notificationManager.notify(builder.buildNotificationWrapper());
     }
 
+    private PendingIntentProvider getPendingIntentProvider(Intent notificationIntent) {
+        // Transient intents use FLAG_CANCEL_CURRENT because the IDs can overlap across sessions.
+        // CANCEL_CURRENT makes sure the PendingIntent is not also reused, and prevents intents from
+        // old sessions from working (e.g. notifications lingering after WebLayer has crashed and
+        // failed to clear them).
+        return PendingIntentProvider.getBroadcast(ContextUtils.getApplicationContext(),
+                mNotificationId, notificationIntent,
+                mIsTransient ? PendingIntent.FLAG_CANCEL_CURRENT : 0);
+    }
+
     /**
      * Helper method to set the sub text on different versions of Android.
      * @param builder The builder to build notification.
@@ -522,6 +537,9 @@
     private void onNativeDestroyed() {
         mNativeDownloadImpl = 0;
         sMap.remove(mNotificationId);
+        if (mIsTransient) {
+            getNotificationManager().cancel(NOTIFICATION_TAG, mNotificationId);
+        }
         // TODO: this should likely notify delegate in some way.
     }
 
@@ -534,6 +552,7 @@
         void pauseImpl(long nativeDownloadImpl);
         void resumeImpl(long nativeDownloadImpl);
         void cancelImpl(long nativeDownloadImpl);
+        void onFinishedImpl(long nativeDownloadImpl, boolean activated);
         String getLocationImpl(long nativeDownloadImpl);
         String getFileNameToReportToUserImpl(long nativeDownloadImpl);
         String getMimeTypeImpl(long nativeDownloadImpl);
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java b/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java
index 38083362..77e3f237 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/settings/WebLayerSiteSettingsDelegate.java
@@ -18,7 +18,6 @@
 import org.chromium.components.content_settings.ContentSettingsType;
 import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
 import org.chromium.components.embedder_support.util.Origin;
-import org.chromium.components.page_info.PageInfoFeatureList;
 import org.chromium.weblayer_private.WebLayerImpl;
 
 import java.util.Collections;
@@ -98,12 +97,6 @@
         return null;
     }
 
-    // TODO(crbug.com/1133798): Remove this when the feature flag is no longer used.
-    @Override
-    public boolean isPageInfoV2Enabled() {
-        return PageInfoFeatureList.isEnabled(PageInfoFeatureList.PAGE_INFO_V2);
-    }
-
     // ManagedPrefrenceDelegate implementation:
     // A no-op because WebLayer doesn't support managed preferences.
 
diff --git a/weblayer/browser/persistent_download.cc b/weblayer/browser/persistent_download.cc
index 316e2ecb..f069256 100644
--- a/weblayer/browser/persistent_download.cc
+++ b/weblayer/browser/persistent_download.cc
@@ -148,6 +148,10 @@
   return nullptr;
 }
 
+void PersistentDownload::OnFinished(bool activated) {
+  // For this type of download, activation is handled purely in Java.
+}
+
 void PersistentDownload::ResumeInternal() {
   if (resume_pending_) {
     resume_pending_ = false;
diff --git a/weblayer/browser/persistent_download.h b/weblayer/browser/persistent_download.h
index 4a6f961a..2e642f8 100644
--- a/weblayer/browser/persistent_download.h
+++ b/weblayer/browser/persistent_download.h
@@ -42,6 +42,7 @@
   bool IsTransient() override;
   GURL GetSourceUrl() override;
   const SkBitmap* GetLargeIcon() override;
+  void OnFinished(bool activated) override;
 
  private:
   explicit PersistentDownload(download::DownloadItem* item);