diff --git a/DEPS b/DEPS
index 6c87a6e..5569f17 100644
--- a/DEPS
+++ b/DEPS
@@ -209,7 +209,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2fed9f62d29a8bee5474f9dd24a55eacf4ffc3b2',
+  'skia_revision': '3d854bade6de6a6c9d5b4458087e463d669de118',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -229,7 +229,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': 'eba8001b8c69a192b5ee4eaff35620e3ccc50b21',
+  'pdfium_revision': 'ae0987e35d7f9707d29ae408cba03327dc1a765f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -280,7 +280,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': 'a68a0035fc2d9f5fe360db514956c861f01b2803',
+  'catapult_revision': 'c1e1d559b46476584ec0eb1d83bd7f43fa5a1b36',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -288,7 +288,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling devtools-frontend
   # and whatever else without interference from each other.
-  'devtools_frontend_revision': 'f1c6145ae8f9df2d720392496b1c742e553f68d0',
+  'devtools_frontend_revision': '4325d86475a5841294a589fd388bb942699c6669',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libprotobuf-mutator
   # and whatever else without interference from each other.
@@ -328,7 +328,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '58ec60ea2336f33503f0a01dd52b1da76dd1dfaf',
+  'dawn_revision': '21ce5d2965485853c2f87e386fd356689486b7c2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -966,7 +966,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1fc595b55c8bc055594d7044f5605740d36f4f5d',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'fe7d709f053dc0d0fe7e577a0236c6cfc2c27908',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1349,7 +1349,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '4690aa4a8390f6a58632cd0ef4022c85ad70f6a0',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'b91884a97a74eee3d9dde816a107e934550ccf26',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1438,7 +1438,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': 'kDu3-fMr7pGnIv414EgU0JsxJIR7OC34dXw3VVXOI5IC'
+              'version': '-Sz2gSN_5yVSHDlitjxUlmZpHuz-F2kFDW6TnmggCZoC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1547,7 +1547,7 @@
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '22ba62ffe79c3881581ab430368bf3764d9533eb',
 
-  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@dd5dea79aaa336ba24376dc4d3fbb74aff859aa9',
+  'src/third_party/vulkan-deps': '{chromium_git}/vulkan-deps@3d799e0e9b08dc14a3efa2e130d288f6ca33d3d0',
 
   'src/third_party/vulkan_memory_allocator':
     Var('chromium_git') + '/external/github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git' + '@' + '732a76d9d3c70d6aa487216495eeb28518349c3a',
@@ -1574,7 +1574,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a03bb38c0e771a0b404753b8e65250e98719870f',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'cfa932f6fc683dc94a884e69712d0cf38e7b5ce4',
+    Var('webrtc_git') + '/src.git' + '@' + '2e929eae1b77ab9fe3ed93471218ece7868900f3',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1635,7 +1635,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@704a3353abe20414ae6d1205c61742b64ea950b8',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@726234f85a4f2c84a756e43cd900338b9890e6d3',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accessibility/autoclick/DIR_METADATA b/ash/accessibility/autoclick/DIR_METADATA
deleted file mode 100644
index 14320f50..0000000
--- a/ash/accessibility/autoclick/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "OS>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ash/accessibility/magnifier/DIR_METADATA b/ash/accessibility/magnifier/DIR_METADATA
index 5661a7bb..681cc01 100644
--- a/ash/accessibility/magnifier/DIR_METADATA
+++ b/ash/accessibility/magnifier/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "OS>Accessibility>Magnifier"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ash/accessibility/sticky_keys/DIR_METADATA b/ash/accessibility/sticky_keys/DIR_METADATA
deleted file mode 100644
index 14320f50..0000000
--- a/ash/accessibility/sticky_keys/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "OS>Accessibility"
-}
-team_email: "chromium-accessibility@chromium.org"
diff --git a/ash/ash_strings_grd/DIR_METADATA b/ash/ash_strings_grd/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/ash/ash_strings_grd/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/ash/assistant/model/BUILD.gn b/ash/assistant/model/BUILD.gn
index 6ca358d..fbce95f 100644
--- a/ash/assistant/model/BUILD.gn
+++ b/ash/assistant/model/BUILD.gn
@@ -51,7 +51,7 @@
     "//chromeos/services/assistant/public/cpp",
     "//chromeos/services/assistant/public/mojom",
     "//chromeos/services/libassistant/public/cpp:structs",
-    "//ui/accessibility/mojom",
+    "//ui/accessibility/mojom:ax_assistant_mojom",
     "//ui/gfx/geometry",
   ]
 }
diff --git a/ash/components/DIR_METADATA b/ash/components/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/ash/components/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/ash/constants/ash_features.cc b/ash/constants/ash_features.cc
index f2bddc3..fe94d881 100644
--- a/ash/constants/ash_features.cc
+++ b/ash/constants/ash_features.cc
@@ -205,11 +205,6 @@
 const base::Feature kCrostiniUseDlc{"CrostiniUseDlc",
                                     base::FEATURE_ENABLED_BY_DEFAULT};
 
-// DLC Service is available for use on the board, prerequisite for the UseDlc
-// flag.
-const base::Feature kCrostiniEnableDlc{"CrostiniEnableDlc",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables or disables using Cryptauth's GetDevicesActivityStatus API.
 const base::Feature kCryptAuthV2DeviceActivityStatus{
     "CryptAuthV2DeviceActivityStatus", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ash/constants/ash_features.h b/ash/constants/ash_features.h
index 00aae4e..d4d5908 100644
--- a/ash/constants/ash_features.h
+++ b/ash/constants/ash_features.h
@@ -106,8 +106,6 @@
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kCrostiniUseDlc;
 COMPONENT_EXPORT(ASH_CONSTANTS)
-extern const base::Feature kCrostiniEnableDlc;
-COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kDiagnosticsApp;
 COMPONENT_EXPORT(ASH_CONSTANTS)
 extern const base::Feature kDisableCryptAuthV1DeviceSync;
diff --git a/ash/content/DIR_METADATA b/ash/content/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/ash/content/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/ash/fast_ink/DIR_METADATA b/ash/fast_ink/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/ash/fast_ink/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/ash/highlighter/DIR_METADATA b/ash/highlighter/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/ash/highlighter/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/ash/keyboard/ui/container_full_width_behavior.cc b/ash/keyboard/ui/container_full_width_behavior.cc
index 64afeba..351b044 100644
--- a/ash/keyboard/ui/container_full_width_behavior.cc
+++ b/ash/keyboard/ui/container_full_width_behavior.cc
@@ -19,8 +19,8 @@
 
 // The height of the area from the bottom of the keyboard where the user can
 // swipe up to access the shelf. Manually calculated to be slightly below
-// the virtual keyboard's space bar.
-constexpr int kSwipeUpGestureAreaHeight = 25;
+// the virtual keyboard's space bar to avoid accidental trigger.
+constexpr int kSwipeUpGestureAreaHeight = 8;
 
 ContainerFullWidthBehavior::ContainerFullWidthBehavior(Delegate* delegate)
     : ContainerBehavior(delegate) {}
diff --git a/ash/public/cpp/file_icon_util.cc b/ash/public/cpp/file_icon_util.cc
index 3d5f4966..8146272 100644
--- a/ash/public/cpp/file_icon_util.cc
+++ b/ash/public/cpp/file_icon_util.cc
@@ -14,7 +14,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/ui/vector_icons/vector_icons.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
@@ -37,6 +36,11 @@
   kFiletypeSites,
 };
 
+struct IconParams {
+  const gfx::VectorIcon& icon;
+  ColorId color_id;
+};
+
 SkColor ResolveColor(ColorId color_id, bool dark_background) {
   switch (color_id) {
     case ColorId::kBlue:
@@ -59,12 +63,7 @@
   }
 }
 
-gfx::ImageSkia GetVectorIconFromIconType(IconType icon, bool dark_background) {
-  struct IconParams {
-    const gfx::VectorIcon& icon;
-    ColorId color_id;
-  };
-
+const std::map<IconType, IconParams>& GetIconTypeToIconParamsMap() {
   // Changes to this map should be reflected in
   // ui/file_manager/file_manager/common/js/file_type.js.
   static const base::NoDestructor<std::map<IconType, IconParams>>
@@ -119,9 +118,13 @@
             IconParams{chromeos::kFiletypeVideoIcon, ColorId::kRed}},
            {IconType::kWord,
             IconParams{chromeos::kFiletypeWordIcon, ColorId::kBlue}}});
+  return *icon_type_to_icon_params;
+}
 
-  const auto& it = icon_type_to_icon_params->find(icon);
-  DCHECK(it != icon_type_to_icon_params->end());
+gfx::ImageSkia GetVectorIconFromIconType(IconType icon, bool dark_background) {
+  const auto& icon_type_to_icon_params = GetIconTypeToIconParamsMap();
+  const auto& it = icon_type_to_icon_params.find(icon);
+  DCHECK(it != icon_type_to_icon_params.end());
 
   const IconParams& params = it->second;
   const gfx::IconDescription description(
@@ -308,4 +311,14 @@
   return GetVectorIconFromIconType(icon_type, dark_background);
 }
 
+SkColor GetIconColorForPath(const base::FilePath& filepath,
+                            bool dark_background) {
+  const auto& icon_type = internal::GetIconTypeForPath(filepath);
+  const auto& icon_type_to_icon_params = GetIconTypeToIconParamsMap();
+  const auto& it = icon_type_to_icon_params.find(icon_type);
+  DCHECK(it != icon_type_to_icon_params.end());
+
+  return ResolveColor(it->second.color_id, dark_background);
+}
+
 }  // namespace ash
diff --git a/ash/public/cpp/file_icon_util.h b/ash/public/cpp/file_icon_util.h
index ce97bba..795379a 100644
--- a/ash/public/cpp/file_icon_util.h
+++ b/ash/public/cpp/file_icon_util.h
@@ -8,6 +8,7 @@
 #include "ash/public/cpp/ash_public_export.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia.h"
 
@@ -70,6 +71,12 @@
 ASH_PUBLIC_EXPORT gfx::ImageSkia GetIconFromType(IconType icon_type,
                                                  bool dark_background);
 
+// Returns the resolved color of the file type icon for the specified
+// `filepath`. If `dark_background` is `true`, lighter foreground colors are
+// used to ensure sufficient contrast.
+ASH_PUBLIC_EXPORT SkColor GetIconColorForPath(const base::FilePath& filepath,
+                                              bool dark_background);
+
 }  // namespace ash
 
 #endif  // ASH_PUBLIC_CPP_FILE_ICON_UTIL_H_
diff --git a/ash/system/microphone_mute/microphone_mute_notification_controller_unittest.cc b/ash/system/microphone_mute/microphone_mute_notification_controller_unittest.cc
index 3651143..d3f75a1 100644
--- a/ash/system/microphone_mute/microphone_mute_notification_controller_unittest.cc
+++ b/ash/system/microphone_mute/microphone_mute_notification_controller_unittest.cc
@@ -232,7 +232,7 @@
   EXPECT_FALSE(GetPopupNotification());
 
   // The notification should be removed if all input streams are removed.
-  LaunchApp(base::nullopt);
+  LaunchApp(absl::nullopt);
   SetNumberOfActiveInputStreams(0);
 
   EXPECT_FALSE(GetNotification());
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index b30d47c..3c81142 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -2138,8 +2138,9 @@
   auto wallpaper_colors = std::make_unique<base::ListValue>();
   for (SkColor color : colors)
     wallpaper_colors->Append(static_cast<double>(color));
-  wallpaper_colors_update->SetWithoutPathExpansion(current_location,
-                                                   std::move(wallpaper_colors));
+  wallpaper_colors_update->SetKey(
+      current_location,
+      base::Value::FromUniquePtrValue(std::move(wallpaper_colors)));
 }
 
 absl::optional<std::vector<SkColor>> WallpaperControllerImpl::GetCachedColors(
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index a6c667c..7174e14b 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -274,8 +274,9 @@
                              const std::string& pref_name) {
   DictionaryPrefUpdate wallpaper_update(pref_service, pref_name);
   auto wallpaper_info_dict = CreateWallpaperInfoDict(info);
-  wallpaper_update->SetWithoutPathExpansion(account_id.GetUserEmail(),
-                                            std::move(wallpaper_info_dict));
+  wallpaper_update->SetKey(
+      account_id.GetUserEmail(),
+      base::Value::FromUniquePtrValue(std::move(wallpaper_info_dict)));
 }
 
 void AssertWallpaperInfoInPrefs(const PrefService* pref_service,
diff --git a/base/task/sequence_manager/DIR_METADATA b/base/task/sequence_manager/DIR_METADATA
deleted file mode 100644
index 8bb4f3e..0000000
--- a/base/task/sequence_manager/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-team_email: "scheduler-dev@chromium.org"
diff --git a/base/task/thread_pool/DIR_METADATA b/base/task/thread_pool/DIR_METADATA
index b934291..6cfe094 100644
--- a/base/task/thread_pool/DIR_METADATA
+++ b/base/task/thread_pool/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Internals>ThreadPool"
 }
-team_email: "scheduler-dev@chromium.org"
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index ba27fea..06faca58 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -102,7 +102,6 @@
 // that's okay.
 
 class BrowserProcessImpl;
-class ChromeJsErrorReportProcessor;
 class ChromeNSSCryptoModuleDelegate;
 class HistogramSynchronizer;
 class KeyStorageLinux;
@@ -480,7 +479,6 @@
   friend class blink::scheduler::WorkerThread;
   friend class chrome_cleaner::ResetShortcutsComponent;
   friend class chrome_cleaner::SystemReportComponent;
-  friend class ::ChromeJsErrorReportProcessor;
   friend class content::BrowserMainLoop;
   friend class content::BrowserProcessIOThread;
   friend class content::ServiceWorkerContextClient;
diff --git a/base/time/DIR_METADATA b/base/time/DIR_METADATA
deleted file mode 100644
index 2aaf8e2eed..0000000
--- a/base/time/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Core"
-}
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
index 3e42d942..67cb096 100644
--- a/base/values_unittest.cc
+++ b/base/values_unittest.cc
@@ -1552,8 +1552,7 @@
 
   {
     DictionaryValue dict;
-    Value* blank_ptr = dict.SetWithoutPathExpansion(
-        "foo.bar", std::make_unique<base::Value>());
+    Value* blank_ptr = dict.SetKey("foo.bar", base::Value());
     EXPECT_EQ(Value::Type::NONE, blank_ptr->type());
   }
 
@@ -1633,7 +1632,7 @@
 TEST(ValuesTest, DictionaryWithoutPathExpansion) {
   DictionaryValue dict;
   dict.Set("this.is.expanded", std::make_unique<Value>());
-  dict.SetWithoutPathExpansion("this.isnt.expanded", std::make_unique<Value>());
+  dict.SetKey("this.isnt.expanded", Value());
 
   EXPECT_FALSE(dict.HasKey("this.is.expanded"));
   EXPECT_TRUE(dict.HasKey("this"));
@@ -2042,8 +2041,7 @@
   // Remove empty lists and dictionaries.
   root->Set("empty_dict", std::make_unique<DictionaryValue>());
   root->Set("empty_list", std::make_unique<ListValue>());
-  root->SetWithoutPathExpansion("a.b.c.d.e",
-                                std::make_unique<DictionaryValue>());
+  root->SetKey("a.b.c.d.e", DictionaryValue());
   root = root->DeepCopyWithoutEmptyChildren();
   EXPECT_TRUE(root->DictEmpty());
 
diff --git a/build/nocompile.gni b/build/nocompile.gni
index 9222105..43193125 100644
--- a/build/nocompile.gni
+++ b/build/nocompile.gni
@@ -75,8 +75,7 @@
   template("nocompile_test") {
     nocompile_target = target_name + "_run_nocompile"
 
-    # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
-    python2_action_foreach(nocompile_target) {
+    action_foreach(nocompile_target) {
       testonly = true
       script = "//tools/nocompile_driver.py"
       sources = invoker.sources
diff --git a/cc/layers/mirror_layer_unittest.cc b/cc/layers/mirror_layer_unittest.cc
index 31d1ea7..deaa92c 100644
--- a/cc/layers/mirror_layer_unittest.cc
+++ b/cc/layers/mirror_layer_unittest.cc
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "base/containers/contains.h"
 #include "cc/animation/animation_host.h"
 #include "cc/layers/mirror_layer.h"
 #include "cc/layers/mirror_layer_impl.h"
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 713d040..9c70a678 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -14,6 +14,7 @@
 #include <set>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/numerics/ranges.h"
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc
index ce16e4e..474b2f0 100644
--- a/cc/metrics/frame_sequence_tracker.cc
+++ b/cc/metrics/frame_sequence_tracker.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_macros.h"
diff --git a/cc/metrics/frame_sequence_tracker_collection.cc b/cc/metrics/frame_sequence_tracker_collection.cc
index 263c421..ed9f7bb 100644
--- a/cc/metrics/frame_sequence_tracker_collection.cc
+++ b/cc/metrics/frame_sequence_tracker_collection.cc
@@ -7,6 +7,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "cc/metrics/compositor_frame_reporting_controller.h"
 #include "cc/metrics/frame_sequence_tracker.h"
diff --git a/chrome/VERSION b/chrome/VERSION
index 50065503..b7f1808 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=92
 MINOR=0
-BUILD=4511
+BUILD=4512
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index dafc21e2..7065e7c 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1196,6 +1196,7 @@
     "//chrome/browser/incognito/interstitial/android:javatests",
     "//chrome/browser/language/android:base_module_java",
     "//chrome/browser/language/android:java",
+    "//chrome/browser/language/android:javatests",
     "//chrome/browser/lens:java",
     "//chrome/browser/locale:java",
     "//chrome/browser/notifications:java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 6afab4e..acd85c25 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -768,9 +768,6 @@
   "java/res/layout/infobar_translate_compact_content.xml",
   "java/res/layout/item_chooser_dialog.xml",
   "java/res/layout/item_chooser_dialog_row.xml",
-  "java/res/layout/language_ask_prompt_content.xml",
-  "java/res/layout/language_ask_prompt_row.xml",
-  "java/res/layout/language_ask_prompt_row_separator.xml",
   "java/res/layout/lightweight_fre_tos.xml",
   "java/res/layout/list_menu_button.xml",
   "java/res/layout/location_bar.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index b71fad2..8c7b4fce 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -738,7 +738,6 @@
   "java/src/org/chromium/chrome/browser/invalidation/ResumableDelayedTaskRunner.java",
   "java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java",
   "java/src/org/chromium/chrome/browser/javascript/WebContextFetcher.java",
-  "java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java",
   "java/src/org/chromium/chrome/browser/lens/LensDebugBridge.java",
   "java/src/org/chromium/chrome/browser/lens/LensPolicyUtils.java",
   "java/src/org/chromium/chrome/browser/login/ChromeHttpAuthHandler.java",
diff --git a/chrome/android/features/ar/DIR_METADATA b/chrome/android/features/ar/DIR_METADATA
index de3b0ac..f5ff1c3 100644
--- a/chrome/android/features/ar/DIR_METADATA
+++ b/chrome/android/features/ar/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Internals>XR>AR"
 }
 team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/features/vr/DIR_METADATA b/chrome/android/features/vr/DIR_METADATA
index 4aece69..b4257dc4 100644
--- a/chrome/android/features/vr/DIR_METADATA
+++ b/chrome/android/features/vr/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Internals>XR>VR"
 }
 team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/res/DIR_METADATA b/chrome/android/java/res/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/res/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/res_app/DIR_METADATA b/chrome/android/java/res_app/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/res_app/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/res_base/DIR_METADATA b/chrome/android/java/res_base/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/res_base/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/res_chromium/DIR_METADATA b/chrome/android/java/res_chromium/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/res_chromium/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/res_chromium_base/DIR_METADATA b/chrome/android/java/res_chromium_base/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/res_chromium_base/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/res_vr/DIR_METADATA b/chrome/android/java/res_vr/DIR_METADATA
index 804da8e1..51a7b01a 100644
--- a/chrome/android/java/res_vr/DIR_METADATA
+++ b/chrome/android/java/res_vr/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>VR"
 }
 team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
index af246dd9..8472c81 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/about_settings/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>Settings"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
index e36aadb9..07b6999 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Accessibility"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
index 823bb4e..f3e3811 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/accessibility_tab_switcher/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>TabSwitcher"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/announcement/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/announcement/DIR_METADATA
index 4c690a8..0213c2ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/announcement/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/announcement/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Notifications"
 }
 team_email: "chrome-notifications@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
index 75169d15..dd20d9d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Internals>Flags"
 }
 team_email: "clank-modularization@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
index 23f0f2f0..60d8c56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Upboarding>VideoTutorials"
 }
 team_email: "chrome-upboarding@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
index b950853..8dc897c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Autofill>UI"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
index a469439..6bafd754 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/background_sync/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>BackgroundSync"
 }
 team_email: "platform-capabilities@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
index 27e0215..8c227be 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Bookmarks"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
index 8749cf8..cc86b52 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Mobile>CustomTabs"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/DIR_METADATA
index 85d9ba1..3ba4fb3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/childaccounts/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Services>Signin"
 }
 team_email: "chrome-signin-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
index c5e1e3e..193fd455 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>CompositedUI"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
index 1ab58a6..f0cdfe5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Search>ContextualSearch"
 }
 team_email: "contextual-search-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/DIR_METADATA
deleted file mode 100644
index f0cdfe5..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Search>ContextualSearch"
-}
-team_email: "contextual-search-dev@chromium.org"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/DIR_METADATA
deleted file mode 100644
index c8d03dd4..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile>CompositedUI"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/DIR_METADATA
deleted file mode 100644
index c8d03dd4..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile>CompositedUI"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/DIR_METADATA
index b9ad4e1..17d5977 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Contacts"
 }
 team_email: "fugu-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA
deleted file mode 100644
index 7a2580a..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/content_capture/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
index d851446..691cac2e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>ContextMenu"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA
index c28e7cd..6b4e54f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/continuous_search/DIR_METADATA
@@ -2,4 +2,3 @@
   component:  "UI>Browser>ContinuousSearch"
 }
 team_email: "csn-dev@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
index c9f79f4..a91e22e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/cryptids/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Joy"
 }
 team_email: "chrome-creation@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
index 217d7c3..3ab39f0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>CustomTabs"
 }
 team_email: "mobile-web-install-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/DIR_METADATA
deleted file mode 100644
index 7a2580a..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
index dcd9225..56645bbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>ReaderMode"
 }
 team_email: "dom-distiller-eng@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
index ff896f2..c6b1123 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/identity_disc/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/identity_disc/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/identity_disc/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/language/OWNERS
deleted file mode 100644
index f1e82d5..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/language/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file://components/language/OWNERS
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/native_page/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/native_page/DIR_METADATA
deleted file mode 100644
index b4dcb712..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/native_page/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
index a810b0ad..d4c3202 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Internals>Installer"
 }
 team_email: "chrome-updates-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DIR_METADATA
deleted file mode 100644
index 07a4669..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
index c19e1828..087172e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Bookmarks"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnercustomizations/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA
deleted file mode 100644
index 7a2580a..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA
index 0198120..1b7c91ce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/query_tiles/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Upboarding>QueryTiles"
 }
 team_email: "chrome-upboarding-eng@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
index af246dd9..8472c81 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>Settings"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
index f2016a9..8809d84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/MainSettings.java
@@ -102,6 +102,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        getActivity().setTitle(R.string.settings);
         mPasswordCheck = PasswordCheckFactory.getOrCreate(new SettingsLauncherImpl());
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
index 36996970..a9bcd18a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/share/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Mobile>Share"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
index 90f1260..167ca6e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Sharing"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
index 82bed135..dc54bb5e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SyncConsentFragment.java
@@ -13,7 +13,6 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.SyncFirstSetupCompleteSource;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
@@ -21,7 +20,6 @@
 import org.chromium.chrome.browser.signin.services.UnifiedConsentServiceBridge;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
 import org.chromium.chrome.browser.sync.settings.ManageSyncSettings;
-import org.chromium.chrome.browser.sync.settings.SyncAndServicesSettings;
 import org.chromium.components.browser_ui.settings.SettingsLauncher;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
@@ -116,16 +114,9 @@
                                 Profile.getLastUsedRegularProfile(), true);
                         SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
                         if (settingsClicked) {
-                            if (ChromeFeatureList.isEnabled(
-                                        ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
-                                settingsLauncher.launchSettingsActivity(getActivity(),
-                                        ManageSyncSettings.class,
-                                        ManageSyncSettings.createArguments(true));
-                            } else {
-                                settingsLauncher.launchSettingsActivity(getActivity(),
-                                        SyncAndServicesSettings.class,
-                                        SyncAndServicesSettings.createArguments(true));
-                            }
+                            settingsLauncher.launchSettingsActivity(getActivity(),
+                                    ManageSyncSettings.class,
+                                    ManageSyncSettings.createArguments(true));
                         } else {
                             ProfileSyncService.get().setFirstSetupComplete(
                                     SyncFirstSetupCompleteSource.BASIC_FLOW);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
index 4cd5b976..cbcab5d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/status_indicator/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>StatusIndicator"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/survey/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/survey/DIR_METADATA
deleted file mode 100644
index 8fc7647..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/survey/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
index e22413d..c6b1123 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
 team_email: "clank-app-team@google.com"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
index d7cefeb5..22dbdc6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tasks/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile>TabSwitcher>Grid"
 }
 team_email: "memex-team@google.com"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DIR_METADATA
index 31157b6a..dab761b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Toolbar"
 }
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/vr/DIR_METADATA
index 804da8e1..51a7b01a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>VR"
 }
 team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA b/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
index cce215f..51b47f7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webshare/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Blink>WebShare"
 }
-os: ANDROID
diff --git a/chrome/android/javatests/DIR_METADATA b/chrome/android/javatests/DIR_METADATA
index a0d027c..5abea21 100644
--- a/chrome/android/javatests/DIR_METADATA
+++ b/chrome/android/javatests/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Test>Android"
 }
-os: ANDROID
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
index ff896f2..e22413d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gesturenav/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Mobile"
 }
 team_email: "clank-app-team@google.com"
-os: ANDROID
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/interstitial/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/interstitial/DIR_METADATA
deleted file mode 100644
index d7aca83..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/incognito/interstitial/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Privacy>Incognito"
-}
-team_email: "chrome-privacy-core@google.com"
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
index 8fc7647..b4dcb712 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/modaldialog/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Mobile"
 }
-os: ANDROID
diff --git a/chrome/android/junit/DIR_METADATA b/chrome/android/junit/DIR_METADATA
index a0d027c..5abea21 100644
--- a/chrome/android/junit/DIR_METADATA
+++ b/chrome/android/junit/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Test>Android"
 }
-os: ANDROID
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
index 23f0f2f0..60d8c56 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/video_tutorials/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Upboarding>VideoTutorials"
 }
 team_email: "chrome-upboarding@chromium.org"
-os: ANDROID
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
index 90f1260..167ca6e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Sharing"
 }
-os: ANDROID
diff --git a/chrome/app/generated_resources_grd/DIR_METADATA b/chrome/app/generated_resources_grd/DIR_METADATA
deleted file mode 100644
index d00c923..0000000
--- a/chrome/app/generated_resources_grd/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>PlatformIntegration"
-}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c418ac2..497e9053 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4313,16 +4313,12 @@
       "apps/app_service/app_service_proxy_chromeos.h",
       "apps/app_service/app_shortcut_item.cc",
       "apps/app_service/app_shortcut_item.h",
-      "apps/app_service/app_web_contents_data.cc",
-      "apps/app_service/app_web_contents_data.h",
       "apps/app_service/arc_activity_adaptive_icon_impl.cc",
       "apps/app_service/arc_activity_adaptive_icon_impl.h",
       "apps/app_service/arc_icon_once_loader.cc",
       "apps/app_service/arc_icon_once_loader.h",
       "apps/app_service/file_utils.cc",
       "apps/app_service/file_utils.h",
-      "apps/app_service/media_requests.cc",
-      "apps/app_service/media_requests.h",
       "apps/app_service/menu_util.cc",
       "apps/app_service/menu_util.h",
       "apps/app_service/paused_apps.cc",
@@ -4785,6 +4781,15 @@
     ]
   }
 
+  if (is_chromeos_ash || is_chromeos_lacros) {
+    sources += [
+      "apps/app_service/app_web_contents_data.cc",
+      "apps/app_service/app_web_contents_data.h",
+      "apps/app_service/media_requests.cc",
+      "apps/app_service/media_requests.h",
+    ]
+  }
+
   if (is_win) {
     libs += [
       "secur32.lib",
@@ -6894,6 +6899,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//ui/gfx",
+    "//ui/gfx:test_support",
   ]
 
   if (!is_android && !is_fuchsia) {
diff --git a/chrome/browser/DIR_METADATA b/chrome/browser/DIR_METADATA
deleted file mode 100644
index 5d4a5f02..0000000
--- a/chrome/browser/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "UI>Browser"
-}
-team_email: "chromium-reviews@chromium.org"
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 94383bd3..3340601 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3305,9 +3305,6 @@
     {"crostini-use-dlc", flag_descriptions::kCrostiniUseDlcName,
      flag_descriptions::kCrostiniUseDlcDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kCrostiniUseDlc)},
-    {"crostini-enable-dlc", flag_descriptions::kCrostiniEnableDlcName,
-     flag_descriptions::kCrostiniEnableDlcDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(chromeos::features::kCrostiniEnableDlc)},
     {"pluginvm-fullscreen", flag_descriptions::kPluginVmFullscreenName,
      flag_descriptions::kPluginVmFullscreenDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kPluginVmFullscreen)},
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc
index b459bb8a..031796f0 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android_utils.cc
@@ -504,7 +504,8 @@
           CreateStringMapFromJava(env, jparameter_names, jparameter_values)),
       SafeConvertJavaStringToNative(env, jexperiment_ids),
       IsCustomTab(web_contents), onboarding_shown, is_direct_action,
-      SafeConvertJavaStringToNative(env, jinitial_url));
+      SafeConvertJavaStringToNative(env, jinitial_url),
+      /* is_in_chrome_triggered = */ false);
 }
 
 bool IsCustomTab(content::WebContents* web_contents) {
diff --git a/chrome/browser/android/vr/arcore_device/DIR_METADATA b/chrome/browser/android/vr/arcore_device/DIR_METADATA
index 7d4b713..1b22cb3c 100644
--- a/chrome/browser/android/vr/arcore_device/DIR_METADATA
+++ b/chrome/browser/android/vr/arcore_device/DIR_METADATA
@@ -1,5 +1,3 @@
 monorail {
   component: "Blink>WebXR>AR"
 }
-team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
index 1fb315b..9203ca8 100644
--- a/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
+++ b/chrome/browser/apps/app_service/fake_lacros_web_apps_host.cc
@@ -44,6 +44,22 @@
   service->GetRemote<crosapi::mojom::AppPublisher>()->OnApps(std::move(apps));
 }
 
+// Test push one test capability_access.
+void PushOneCapabilityAccess() {
+  auto* service = chromeos::LacrosService::Get();
+
+  std::vector<apps::mojom::CapabilityAccessPtr> capability_accesses;
+
+  apps::mojom::CapabilityAccessPtr capability_access =
+      apps::mojom::CapabilityAccess::New();
+  capability_access->app_id = "abcdefg";
+  capability_access->camera = apps::mojom::OptionalBool::kTrue;
+  capability_access->microphone = apps::mojom::OptionalBool::kFalse;
+  capability_accesses.push_back(std::move(capability_access));
+  service->GetRemote<crosapi::mojom::AppPublisher>()->OnCapabilityAccesses(
+      std::move(capability_accesses));
+}
+
 }  // namespace
 
 namespace apps {
@@ -66,6 +82,7 @@
     service->GetRemote<crosapi::mojom::AppPublisher>()->RegisterAppController(
         receiver_.BindNewPipeAndPassRemote());
     PushOneApp();
+    PushOneCapabilityAccess();
   }
 }
 
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
index 7fcb1bb5..bb9eb89 100644
--- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
+++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.cc
@@ -145,6 +145,11 @@
       plugin_vm::prefs::kPluginVmImageExists,
       base::BindRepeating(&PluginVmApps::OnPluginVmConfiguredChanged,
                           base::Unretained(this)));
+  for (const PermissionInfo& info : permission_infos) {
+    pref_registrar_.Add(info.pref_name,
+                        base::BindRepeating(&PluginVmApps::OnPermissionChanged,
+                                            base::Unretained(this)));
+  }
 
   is_allowed_ = plugin_vm::PluginVmFeatures::Get()->IsAllowed(profile_);
 }
@@ -211,12 +216,6 @@
   }
 
   profile_->GetPrefs()->SetBoolean(pref_name, permission_ptr->value);
-
-  apps::mojom::AppPtr app = apps::mojom::App::New();
-  app->app_type = apps::mojom::AppType::kPluginVm;
-  app->app_id = plugin_vm::kPluginVmShelfAppId;
-  PopulatePermissions(app.get(), profile_);
-  Publish(std::move(app), subscribers_);
 }
 
 void PluginVmApps::Uninstall(const std::string& app_id,
@@ -337,4 +336,12 @@
   Publish(std::move(app), subscribers_);
 }
 
+void PluginVmApps::OnPermissionChanged() {
+  apps::mojom::AppPtr app = apps::mojom::App::New();
+  app->app_type = apps::mojom::AppType::kPluginVm;
+  app->app_id = plugin_vm::kPluginVmShelfAppId;
+  PopulatePermissions(app.get(), profile_);
+  Publish(std::move(app), subscribers_);
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
index ec84dec..5b0357f 100644
--- a/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
+++ b/chrome/browser/apps/app_service/publishers/plugin_vm_apps.h
@@ -76,6 +76,7 @@
       bool new_icon_key);
   void OnPluginVmAllowedChanged(bool is_allowed);
   void OnPluginVmConfiguredChanged();
+  void OnPermissionChanged();
 
   mojo::RemoteSet<apps::mojom::Subscriber> subscribers_;
 
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
index 6012289e..5deee4a 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.cc
@@ -30,6 +30,15 @@
   return clone_to;
 }
 
+std::vector<apps::mojom::CapabilityAccessPtr> CloneCapabilityAccesses(
+    const std::vector<apps::mojom::CapabilityAccessPtr>& clone_from) {
+  std::vector<apps::mojom::CapabilityAccessPtr> clone_to;
+  for (const auto& capability_access : clone_from) {
+    clone_to.push_back(capability_access->Clone());
+  }
+  return clone_to;
+}
+
 }  // namespace
 
 namespace apps {
@@ -133,6 +142,15 @@
       &WebAppsCrosapi::OnControllerDisconnected, base::Unretained(this)));
 }
 
+void WebAppsCrosapi::OnCapabilityAccesses(
+    std::vector<apps::mojom::CapabilityAccessPtr> deltas) {
+  if (!base::FeatureList::IsEnabled(features::kWebAppsCrosapi))
+    return;
+  for (auto& subscriber : subscribers_) {
+    subscriber->OnCapabilityAccesses(CloneCapabilityAccesses(deltas));
+  }
+}
+
 void WebAppsCrosapi::OnCrosapiDisconnected() {
   receiver_.reset();
   controller_.reset();
diff --git a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
index b6c6aee..ff5dab08 100644
--- a/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
+++ b/chrome/browser/apps/app_service/publishers/web_apps_crosapi.h
@@ -5,12 +5,16 @@
 #ifndef CHROME_BROWSER_APPS_APP_SERVICE_PUBLISHERS_WEB_APPS_CROSAPI_H_
 #define CHROME_BROWSER_APPS_APP_SERVICE_PUBLISHERS_WEB_APPS_CROSAPI_H_
 
+#include <string>
+#include <vector>
+
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/apps/app_service/icon_key_util.h"
 #include "chromeos/crosapi/mojom/app_service.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/services/app_service/public/cpp/publisher_base.h"
 #include "components/services/app_service/public/mojom/app_service.mojom-forward.h"
+#include "components/services/app_service/public/mojom/types.mojom-forward.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
@@ -66,6 +70,8 @@
   void OnApps(std::vector<apps::mojom::AppPtr> deltas) override;
   void RegisterAppController(
       mojo::PendingRemote<crosapi::mojom::AppController> controller) override;
+  void OnCapabilityAccesses(
+      std::vector<apps::mojom::CapabilityAccessPtr> deltas) override;
 
   void OnCrosapiDisconnected();
   void OnControllerDisconnected();
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host.cc b/chrome/browser/apps/app_service/web_apps_publisher_host.cc
index 4b0fe8dd..8ce915e 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host.cc
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host.cc
@@ -11,12 +11,15 @@
 #include "chrome/browser/apps/app_service/web_apps_utils.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/common/chrome_features.h"
 #include "chromeos/lacros/lacros_service.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
 namespace apps {
@@ -74,12 +77,14 @@
         service->GetRemote<crosapi::mojom::AppPublisher>().get();
   }
 
+  media_dispatcher_.Observe(MediaCaptureDevicesDispatcher::GetInstance());
+
   provider_->on_registry_ready().Post(
       FROM_HERE, base::BindOnce(&WebAppsPublisherHost::OnReady,
                                 weak_ptr_factory_.GetWeakPtr()));
   registrar_observation_.Observe(&registrar());
   content_settings_observation_.Observe(
-      HostContentSettingsMapFactory::GetForProfile(profile_));
+      HostContentSettingsMapFactory::GetForProfile(profile()));
 }
 
 web_app::WebAppRegistrar& WebAppsPublisherHost::registrar() const {
@@ -113,7 +118,7 @@
     return;
   }
 
-  apps_util::UninstallWebApp(profile_, web_app, uninstall_source,
+  apps_util::UninstallWebApp(profile(), web_app, uninstall_source,
                              clear_site_data, report_abuse);
 }
 
@@ -143,6 +148,12 @@
     return;
   }
 
+  // TODO(crbug.com/1194709): Keep consistent behavior with WebAppsChromeOs:
+  // remove notifications for app, update paused apps.
+
+  auto result = media_requests_.RemoveRequests(app_id);
+  ModifyCapabilityAccess(app_id, result.camera, result.microphone);
+
   Publish(
       apps_util::ConvertUninstalledWebApp(web_app, apps::mojom::AppType::kWeb));
 }
@@ -192,7 +203,7 @@
       apps::mojom::AppPtr app = apps::mojom::App::New();
       app->app_type = apps::mojom::AppType::kWeb;
       app->app_id = web_app.app_id();
-      apps_util::PopulateWebAppPermissions(profile_, &web_app,
+      apps_util::PopulateWebAppPermissions(profile(), &web_app,
                                            &app->permissions);
 
       Publish(std::move(app));
@@ -200,6 +211,63 @@
   }
 }
 
+void WebAppsPublisherHost::OnRequestUpdate(
+    int render_process_id,
+    int render_frame_id,
+    blink::mojom::MediaStreamType stream_type,
+    const content::MediaRequestState state) {
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(
+          content::RenderFrameHost::FromID(render_process_id, render_frame_id));
+
+  if (!web_contents) {
+    return;
+  }
+
+  absl::optional<web_app::AppId> app_id =
+      web_app::FindInstalledAppWithUrlInScope(profile(), web_contents->GetURL(),
+                                              /*window_only=*/false);
+  if (!app_id.has_value()) {
+    return;
+  }
+
+  const web_app::WebApp* web_app = GetWebApp(app_id.value());
+  if (!web_app) {
+    return;
+  }
+
+  if (media_requests_.IsNewRequest(app_id.value(), web_contents, state)) {
+    content::WebContentsUserData<AppWebContentsData>::CreateForWebContents(
+        web_contents, this);
+  }
+
+  auto result = media_requests_.UpdateRequests(app_id.value(), web_contents,
+                                               stream_type, state);
+  ModifyCapabilityAccess(app_id.value(), result.camera, result.microphone);
+}
+
+void WebAppsPublisherHost::OnWebContentsDestroyed(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+
+  absl::optional<web_app::AppId> app_id =
+      web_app::FindInstalledAppWithUrlInScope(
+          profile(), web_contents->GetLastCommittedURL(),
+          /*window_only=*/false);
+  if (!app_id.has_value()) {
+    return;
+  }
+
+  const web_app::WebApp* web_app = GetWebApp(app_id.value());
+  if (!web_app) {
+    return;
+  }
+
+  auto result =
+      media_requests_.OnWebContentsDestroyed(app_id.value(), web_contents);
+  ModifyCapabilityAccess(app_id.value(), result.camera, result.microphone);
+}
+
 const web_app::WebApp* WebAppsPublisherHost::GetWebApp(
     const web_app::AppId& app_id) const {
   return registrar().GetAppById(app_id);
@@ -209,7 +277,7 @@
     const web_app::WebApp* web_app,
     apps::mojom::Readiness readiness) {
   apps::mojom::AppPtr app = apps_util::ConvertWebApp(
-      profile_, web_app, apps::mojom::AppType::kWeb, readiness);
+      profile(), web_app, apps::mojom::AppType::kWeb, readiness);
   app->icon_key = icon_key_factory_.MakeIconKey(GetIconEffects(web_app));
   return app;
 }
@@ -224,4 +292,36 @@
   remote_publisher_->OnApps(std::move(apps));
 }
 
+void WebAppsPublisherHost::ModifyCapabilityAccess(
+    const std::string& app_id,
+    absl::optional<bool> accessing_camera,
+    absl::optional<bool> accessing_microphone) {
+  if (!remote_publisher_) {
+    return;
+  }
+
+  if (!accessing_camera.has_value() && !accessing_microphone.has_value()) {
+    return;
+  }
+
+  std::vector<apps::mojom::CapabilityAccessPtr> capability_accesses;
+  auto capability_access = apps::mojom::CapabilityAccess::New();
+  capability_access->app_id = app_id;
+
+  if (accessing_camera.has_value()) {
+    capability_access->camera = accessing_camera.value()
+                                    ? apps::mojom::OptionalBool::kTrue
+                                    : apps::mojom::OptionalBool::kFalse;
+  }
+
+  if (accessing_microphone.has_value()) {
+    capability_access->microphone = accessing_microphone.value()
+                                        ? apps::mojom::OptionalBool::kTrue
+                                        : apps::mojom::OptionalBool::kFalse;
+  }
+
+  capability_accesses.push_back(std::move(capability_access));
+  remote_publisher_->OnCapabilityAccesses(std::move(capability_accesses));
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host.h b/chrome/browser/apps/app_service/web_apps_publisher_host.h
index c6847ed..a47d91e 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host.h
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host.h
@@ -12,7 +12,10 @@
 #include "base/scoped_observation.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
+#include "chrome/browser/apps/app_service/app_web_contents_data.h"
 #include "chrome/browser/apps/app_service/icon_key_util.h"
+#include "chrome/browser/apps/app_service/media_requests.h"
+#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registrar_observer.h"
 #include "chrome/browser/web_applications/components/web_app_id.h"
@@ -22,10 +25,15 @@
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/services/app_service/public/mojom/types.mojom.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
 
 class ContentSettingsPattern;
 class Profile;
 
+namespace content {
+class WebContents;
+}  // namespace content
+
 namespace web_app {
 class WebApp;
 class WebAppProvider;
@@ -38,7 +46,9 @@
 // WebAppsCrosapi to inform the Ash browser of the current set of web apps.
 class WebAppsPublisherHost : public crosapi::mojom::AppController,
                              public web_app::AppRegistrarObserver,
-                             content_settings::Observer {
+                             public content_settings::Observer,
+                             public MediaCaptureDevicesDispatcher::Observer,
+                             public AppWebContentsData::Client {
  public:
   explicit WebAppsPublisherHost(Profile* profile);
   WebAppsPublisherHost(const WebAppsPublisherHost&) = delete;
@@ -47,6 +57,7 @@
 
   void Init();
 
+  Profile* profile() { return profile_; }
   web_app::WebAppRegistrar& registrar() const;
 
   void SetPublisherForTesting(crosapi::mojom::AppPublisher* publisher);
@@ -79,11 +90,24 @@
 
   // TODO(crbug.com/1194709): Add more overrides, guided by WebAppsChromeOs.
 
+  // MediaCaptureDevicesDispatcher::Observer:
+  void OnRequestUpdate(int render_process_id,
+                       int render_frame_id,
+                       blink::mojom::MediaStreamType stream_type,
+                       const content::MediaRequestState state) override;
+
+  // AppWebContentsData::Client:
+  void OnWebContentsDestroyed(content::WebContents* contents) override;
+
   const web_app::WebApp* GetWebApp(const web_app::AppId& app_id) const;
   apps::mojom::AppPtr Convert(const web_app::WebApp* web_app,
                               apps::mojom::Readiness readiness);
   void Publish(apps::mojom::AppPtr app);
 
+  void ModifyCapabilityAccess(const std::string& app_id,
+                              absl::optional<bool> accessing_camera,
+                              absl::optional<bool> accessing_microphone);
+
   Profile* const profile_;
   web_app::WebAppProvider* const provider_;
   crosapi::mojom::AppPublisher* remote_publisher_ = nullptr;
@@ -98,6 +122,12 @@
   base::ScopedObservation<HostContentSettingsMap, content_settings::Observer>
       content_settings_observation_{this};
 
+  base::ScopedObservation<MediaCaptureDevicesDispatcher,
+                          MediaCaptureDevicesDispatcher::Observer>
+      media_dispatcher_{this};
+
+  MediaRequests media_requests_;
+
   base::WeakPtrFactory<WebAppsPublisherHost> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc b/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
index 4b737b9..c01f75a1 100644
--- a/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
+++ b/chrome/browser/apps/app_service/web_apps_publisher_host_browsertest.cc
@@ -10,14 +10,19 @@
 #include <vector>
 
 #include "base/callback_helpers.h"
+#include "base/location.h"
 #include "base/notreached.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/values.h"
 #include "chrome/browser/apps/app_service/app_icon_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h"
 #include "chrome/browser/web_applications/components/app_registry_controller.h"
@@ -34,6 +39,11 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "components/webapps/browser/installable/installable_metrics.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "url/gurl.h"
@@ -50,13 +60,21 @@
     run_loop_ = std::make_unique<base::RunLoop>();
   }
 
-  const std::vector<apps::mojom::AppPtr>& get_deltas() const { return deltas_; }
+  const std::vector<apps::mojom::AppPtr>& get_deltas() const {
+    return app_deltas_;
+  }
+
+  const std::vector<apps::mojom::CapabilityAccessPtr>&
+  get_capability_access_deltas() const {
+    return capability_access_deltas_;
+  }
 
  private:
   // crosapi::mojom::AppPublisher:
   void OnApps(std::vector<apps::mojom::AppPtr> deltas) override {
-    deltas_.insert(deltas_.end(), std::make_move_iterator(deltas.begin()),
-                   std::make_move_iterator(deltas.end()));
+    app_deltas_.insert(app_deltas_.end(),
+                       std::make_move_iterator(deltas.begin()),
+                       std::make_move_iterator(deltas.end()));
     run_loop_->Quit();
   }
 
@@ -65,7 +83,16 @@
     NOTIMPLEMENTED();
   }
 
-  std::vector<apps::mojom::AppPtr> deltas_;
+  void OnCapabilityAccesses(
+      std::vector<apps::mojom::CapabilityAccessPtr> deltas) override {
+    capability_access_deltas_.insert(capability_access_deltas_.end(),
+                                     std::make_move_iterator(deltas.begin()),
+                                     std::make_move_iterator(deltas.end()));
+    run_loop_->Quit();
+  }
+
+  std::vector<apps::mojom::AppPtr> app_deltas_;
+  std::vector<apps::mojom::CapabilityAccessPtr> capability_access_deltas_;
   std::unique_ptr<base::RunLoop> run_loop_;
 };
 
@@ -286,4 +313,54 @@
             static_cast<uint32_t>(apps::mojom::TriState::kAllow));
 }
 
+IN_PROC_BROWSER_TEST_F(WebAppsPublisherHostBrowserTest, MediaRequest) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  const GURL app_url = embedded_test_server()->GetURL("/web_apps/basic.html");
+  web_app::AppId app_id =
+      web_app::InstallWebAppFromManifest(browser(), app_url);
+  Browser* browser = LaunchWebAppBrowserAndWait(app_id);
+  content::RenderFrameHost* render_frame_host =
+      browser->tab_strip_model()->GetActiveWebContents()->GetMainFrame();
+  const int render_process_id = render_frame_host->GetProcess()->GetID();
+  const int render_frame_id = render_frame_host->GetRoutingID();
+
+  MockAppPublisher mock_app_publisher;
+  WebAppsPublisherHost web_apps_publisher_host(profile());
+  web_apps_publisher_host.SetPublisherForTesting(&mock_app_publisher);
+  web_apps_publisher_host.Init();
+  mock_app_publisher.Wait();
+  EXPECT_EQ(mock_app_publisher.get_deltas().size(), 1U);
+
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindLambdaForTesting([render_process_id, render_frame_id,
+                                             app_url]() {
+        MediaCaptureDevicesDispatcher::GetInstance()
+            ->OnMediaRequestStateChanged(
+                render_process_id, render_frame_id,
+                /*page_request_id=*/0, app_url,
+                blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE,
+                content::MEDIA_REQUEST_STATE_DONE);
+      }));
+  mock_app_publisher.Wait();
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().size(), 1U);
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->app_id,
+            app_id);
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->camera,
+            apps::mojom::OptionalBool::kUnknown);
+  EXPECT_EQ(
+      mock_app_publisher.get_capability_access_deltas().back()->microphone,
+      apps::mojom::OptionalBool::kTrue);
+
+  browser->tab_strip_model()->CloseAllTabs();
+  mock_app_publisher.Wait();
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().size(), 2U);
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->app_id,
+            app_id);
+  EXPECT_EQ(mock_app_publisher.get_capability_access_deltas().back()->camera,
+            apps::mojom::OptionalBool::kUnknown);
+  EXPECT_EQ(
+      mock_app_publisher.get_capability_access_deltas().back()->microphone,
+      apps::mojom::OptionalBool::kFalse);
+}
+
 }  // namespace apps
diff --git a/chrome/browser/apps/digital_goods/DIR_METADATA b/chrome/browser/apps/digital_goods/DIR_METADATA
deleted file mode 100644
index 00289ad..0000000
--- a/chrome/browser/apps/digital_goods/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Platform>Apps>Foundation"
-}
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc
index bd71e98f..2e28252d 100644
--- a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc
+++ b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_api.cc
@@ -598,7 +598,8 @@
     }
   }
   std::unique_ptr<base::DictionaryValue> results(new base::DictionaryValue);
-  results->SetWithoutPathExpansion("mediaFileSystems", std::move(list));
+  results->SetKey("mediaFileSystems",
+                  base::Value::FromUniquePtrValue(std::move(list)));
   results->SetKey("selectedFileSystemIndex", base::Value(index));
   Respond(OneArgument(base::Value::FromUniquePtrValue(std::move(results))));
 }
diff --git a/chrome/browser/ash/crosapi/automation_ash.cc b/chrome/browser/ash/crosapi/automation_ash.cc
index 976c1575..9e625c42 100644
--- a/chrome/browser/ash/crosapi/automation_ash.cc
+++ b/chrome/browser/ash/crosapi/automation_ash.cc
@@ -91,6 +91,18 @@
       ui::AXTreeID::FromToken(tree_id), nullptr);
 }
 
+void AutomationAsh::DispatchActionResult(
+    const ui::AXActionData& already_handled_action_data,
+    bool result) {
+  // This prototype method is only implemented on developer builds of Chrome. We
+  // check for this by checking that the build of Chrome is unbranded.
+  if (chrome::GetChannel() != version_info::Channel::UNKNOWN)
+    return;
+
+  extensions::AutomationEventRouter::GetInstance()->DispatchActionResult(
+      already_handled_action_data, result);
+}
+
 // Forwards an action to all crosapi clients. This has no effect on production
 // builds of chrome. It exists for prototyping for developers.
 void AutomationAsh::PerformAction(const ui::AXTreeID& tree_id,
diff --git a/chrome/browser/ash/crosapi/automation_ash.h b/chrome/browser/ash/crosapi/automation_ash.h
index 3f683e5..98d8a3d 100644
--- a/chrome/browser/ash/crosapi/automation_ash.h
+++ b/chrome/browser/ash/crosapi/automation_ash.h
@@ -46,6 +46,8 @@
                              const std::string& window_id) override;
   void DispatchTreeDestroyedEvent(
       const base::UnguessableToken& tree_id) override;
+  void DispatchActionResult(const ui::AXActionData& already_handled_action_data,
+                            bool result) override;
 
   // ui::AXActionHandlerObserver:
   void PerformAction(const ui::AXTreeID& tree_id,
diff --git a/chrome/browser/ash/crostini/crostini_installer.cc b/chrome/browser/ash/crostini/crostini_installer.cc
index 4779fff1..2b6c7bf 100644
--- a/chrome/browser/ash/crostini/crostini_installer.cc
+++ b/chrome/browser/ash/crostini/crostini_installer.cc
@@ -244,6 +244,10 @@
   // this pref to the empty list.
   profile_->GetPrefs()->Set(crostini::prefs::kCrostiniContainers,
                             base::Value(base::Value::Type::LIST));
+
+  // Reset mic permissions, we don't want it to persist across
+  // re-installation.
+  profile_->GetPrefs()->SetBoolean(prefs::kCrostiniMicAllowed, false);
 }
 
 void CrostiniInstaller::Cancel(base::OnceClosure callback) {
diff --git a/chrome/browser/ash/crostini/termina_installer.cc b/chrome/browser/ash/crostini/termina_installer.cc
index 4321f08..522816c 100644
--- a/chrome/browser/ash/crostini/termina_installer.cc
+++ b/chrome/browser/ash/crostini/termina_installer.cc
@@ -356,12 +356,6 @@
 
 void TerminaInstaller::RemoveDlcIfPresent(base::OnceCallback<void()> callback,
                                           UninstallResult* result) {
-  if (!base::FeatureList::IsEnabled(chromeos::features::kCrostiniEnableDlc)) {
-    // No DLC service, so be a no-op.
-    *result = true;
-    std::move(callback).Run();
-    return;
-  }
   chromeos::DlcserviceClient::Get()->GetExistingDlcs(base::BindOnce(
       [](base::WeakPtr<TerminaInstaller> weak_this,
          base::OnceCallback<void()> callback, UninstallResult* result,
diff --git a/chrome/browser/ash/crostini/termina_installer_unittest.cc b/chrome/browser/ash/crostini/termina_installer_unittest.cc
index 84011b9..b2a1239 100644
--- a/chrome/browser/ash/crostini/termina_installer_unittest.cc
+++ b/chrome/browser/ash/crostini/termina_installer_unittest.cc
@@ -39,7 +39,7 @@
   void SetUp() override {
     this->CommonSetUp();
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{chromeos::features::kCrostiniEnableDlc},
+        /*enabled_features=*/{},
         /*disabled_features=*/{});
   }
 
@@ -166,8 +166,7 @@
   void SetUp() override {
     this->CommonSetUp();
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{chromeos::features::kCrostiniUseDlc,
-                              chromeos::features::kCrostiniEnableDlc},
+        /*enabled_features=*/{chromeos::features::kCrostiniUseDlc},
         /*disabled_features=*/{});
   }
 };
@@ -180,25 +179,11 @@
   void SetUp() override {
     this->CommonSetUp();
     feature_list_.InitWithFeatures(
-        /*enabled_features=*/{chromeos::features::kCrostiniEnableDlc},
+        /*enabled_features=*/{},
         /*disabled_features=*/{chromeos::features::kCrostiniUseDlc});
   }
 };
 
-// Specialization of TerminaInstallTest that enables installing via DLC but DLC
-// isn't enabled
-class TerminaDlcDisabledInstallTest : public TerminaInstallTest {
- public:
-  TerminaDlcDisabledInstallTest() = default;
-
-  void SetUp() override {
-    this->CommonSetUp();
-    feature_list_.InitWithFeatures(
-        /*enabled_features=*/{chromeos::features::kCrostiniUseDlc},
-        /*disabled_features=*/{chromeos::features::kCrostiniEnableDlc});
-  }
-};
-
 TEST_F(TerminaInstallTest, UninstallWithNothingInstalled) {
   termina_installer_.Uninstall(
       base::BindOnce(&TerminaInstallTest::ExpectTrue, base::Unretained(this)));
@@ -264,16 +249,6 @@
   run_loop_.Run();
 }
 
-TEST_F(TerminaDlcDisabledInstallTest,
-       UninstallWithDlcDisabledUninstallErrorDoesntFail) {
-  InjectDlc();
-  fake_dlc_client_->set_uninstall_error("An error");
-
-  termina_installer_.Uninstall(
-      base::BindOnce(&TerminaInstallTest::ExpectTrue, base::Unretained(this)));
-  run_loop_.Run();
-}
-
 TEST_F(TerminaInstallTest, UninstallWithBothInstalled) {
   component_manager_->SetRegisteredComponents(
       {imageloader::kTerminaComponentName});
diff --git a/chrome/browser/ash/file_system_provider/registry_unittest.cc b/chrome/browser/ash/file_system_provider/registry_unittest.cc
index bab92b6..e897a60 100644
--- a/chrome/browser/ash/file_system_provider/registry_unittest.cc
+++ b/chrome/browser/ash/file_system_provider/registry_unittest.cc
@@ -80,16 +80,19 @@
       persistent_origins_value->AppendString(subscriber_it.first.spec());
   }
 
-  watcher_value->SetWithoutPathExpansion(kPrefKeyWatcherPersistentOrigins,
-                                         std::move(persistent_origins_value));
+  watcher_value->SetKey(
+      kPrefKeyWatcherPersistentOrigins,
+      base::Value::FromUniquePtrValue(std::move(persistent_origins_value)));
   auto watchers = std::make_unique<base::DictionaryValue>();
-  watchers->SetWithoutPathExpansion(watcher.entry_path.value(),
-                                    std::move(watcher_value));
-  file_system->SetWithoutPathExpansion(kPrefKeyWatchers, std::move(watchers));
+  watchers->SetKey(watcher.entry_path.value(),
+                   base::Value::FromUniquePtrValue(std::move(watcher_value)));
+  file_system->SetKey(kPrefKeyWatchers,
+                      base::Value::FromUniquePtrValue(std::move(watchers)));
   auto file_systems = std::make_unique<base::DictionaryValue>();
-  file_systems->SetWithoutPathExpansion(kFileSystemId, std::move(file_system));
-  extensions.SetWithoutPathExpansion(kProviderId.ToString(),
-                                     std::move(file_systems));
+  file_systems->SetKey(kFileSystemId,
+                       base::Value::FromUniquePtrValue(std::move(file_system)));
+  extensions.SetKey(kProviderId.ToString(),
+                    base::Value::FromUniquePtrValue(std::move(file_systems)));
   pref_service->Set(prefs::kFileSystemProviderMounted, extensions);
 }
 
diff --git a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
index 258de39..2c888b5 100644
--- a/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
+++ b/chrome/browser/ash/login/users/avatar/user_image_manager_impl.cc
@@ -462,7 +462,7 @@
                std::make_unique<base::Value>(image_url_.spec()));
   DictionaryPrefUpdate update(g_browser_process->local_state(),
                               kUserImageProperties);
-  update->SetWithoutPathExpansion(user_id(), std::move(entry));
+  update->SetKey(user_id(), base::Value::FromUniquePtrValue(std::move(entry)));
 
   parent_->user_manager_->NotifyLocalStateChanged();
 }
diff --git a/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc b/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
index ea1e124..5272433 100644
--- a/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
+++ b/chrome/browser/ash/plugin_vm/plugin_vm_installer.cc
@@ -132,6 +132,11 @@
   if (content::GetNetworkConnectionTracker()->IsOffline())
     return FailureReason::OFFLINE;
 
+  // Reset camera/mic permissions, we don't want it to persist across
+  // re-installation.
+  profile_->GetPrefs()->SetBoolean(prefs::kPluginVmCameraAllowed, false);
+  profile_->GetPrefs()->SetBoolean(prefs::kPluginVmMicAllowed, false);
+
   // Request wake lock when state_ goes to kInstalling, and cancel it when state
   // goes back to kIdle.
   GetWakeLock()->RequestWakeLock();
diff --git a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
index f002f3ea..936ce32 100644
--- a/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
+++ b/chrome/browser/ash/web_applications/media_app/media_app_integration_browsertest.cc
@@ -246,6 +246,22 @@
   MediaAppUiBrowserTest::EvalJsInAppFrame(
       app, base::ReplaceStringPlaceholders(kClickButton, {selector}, nullptr));
 }
+
+// Returns true if the button on the app bar with the specified selector has the
+// 'on' attribute (indicating it's styled as active).
+bool isAppBarButtonOn(content::WebContents* app, const std::string& selector) {
+  constexpr char kIsButtonOn[] = R"(
+    (async () => {
+      const button =
+          await getNode('$1', ['backlight-app-bar', 'backlight-app']);
+      return button.hasAttribute('on');
+    })();
+  )";
+  return MediaAppUiBrowserTest::EvalJsInAppFrame(
+             app,
+             base::ReplaceStringPlaceholders(kIsButtonOn, {selector}, nullptr))
+      .ExtractBool();
+}
 }  // namespace
 
 IN_PROC_BROWSER_TEST_P(MediaAppIntegrationTest, LoadsInkForImageAnnotation) {
@@ -298,15 +314,17 @@
   )";
   EXPECT_EQ(false,
             MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen));
-
-  // Expect info panel to be open after clicking info button.
   // icon-button ids are calculated from a hash of the button labels. Id is used
   // because the UI toolkit has loose guarantees about where the actual label
   // appears in the shadow DOM.
   const std::string kInfoButtonSelector = "#icon-button-2283726";
+  EXPECT_EQ(false, isAppBarButtonOn(app, kInfoButtonSelector));
+
+  // Expect info panel to be open after clicking info button.
   clickAppBarButton(app, kInfoButtonSelector);
   EXPECT_EQ(true,
             MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen));
+  EXPECT_EQ(true, isAppBarButtonOn(app, kInfoButtonSelector));
 
   // Expect info panel to be closed after clicking info button again.
   // After closing we must wait for the DOM update because the panel doesn't
@@ -321,6 +339,7 @@
   MediaAppUiBrowserTest::EvalJsInAppFrame(app, kWaitForImageHandlerUpdate);
   EXPECT_EQ(false,
             MediaAppUiBrowserTest::EvalJsInAppFrame(app, kHasInfoPanelOpen));
+  EXPECT_EQ(false, isAppBarButtonOn(app, kInfoButtonSelector));
 }
 #endif  // BUILDFLAG(ENABLE_CROS_MEDIA_APP)
 
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.cc b/chrome/browser/autofill/mock_autofill_popup_controller.cc
index 952c8258..684fc31 100644
--- a/chrome/browser/autofill/mock_autofill_popup_controller.cc
+++ b/chrome/browser/autofill/mock_autofill_popup_controller.cc
@@ -7,9 +7,8 @@
 
 namespace autofill {
 
-MockAutofillPopupController::MockAutofillPopupController() {
-  gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
-}
+MockAutofillPopupController::MockAutofillPopupController()
+    : default_font_desc_setter_("Arial, Times New Roman, 15px") {}
 
 MockAutofillPopupController::~MockAutofillPopupController() = default;
 
diff --git a/chrome/browser/autofill/mock_autofill_popup_controller.h b/chrome/browser/autofill/mock_autofill_popup_controller.h
index 47c73ea..864a1056 100644
--- a/chrome/browser/autofill/mock_autofill_popup_controller.h
+++ b/chrome/browser/autofill/mock_autofill_popup_controller.h
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/ui/suggestion.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/test/gfx_util.h"
 
 namespace autofill {
 
@@ -84,6 +85,7 @@
 
  private:
   std::vector<autofill::Suggestion> suggestions_;
+  gfx::ScopedDefaultFontDescription default_font_desc_setter_;
 
   base::WeakPtrFactory<MockAutofillPopupController> weak_ptr_factory_{this};
 };
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index 74978a33..3dc0fd7 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -634,7 +634,7 @@
   auto dict = std::make_unique<base::DictionaryValue>();
   dict->SetString(kUrlKey, background_contents->GetURL().spec());
   dict->SetString(kFrameNameKey, contents_map_[appid].frame_name);
-  pref->SetWithoutPathExpansion(appid, std::move(dict));
+  pref->SetKey(appid, base::Value::FromUniquePtrValue(std::move(dict)));
 }
 
 bool BackgroundContentsService::HasRegisteredBackgroundContents(
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 08fd531..28132496 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2309,6 +2309,8 @@
     "full_restore/arc_ghost_window_delegate.h",
     "full_restore/arc_ghost_window_shell_surface.cc",
     "full_restore/arc_ghost_window_shell_surface.h",
+    "full_restore/arc_ghost_window_view.cc",
+    "full_restore/arc_ghost_window_view.h",
     "full_restore/arc_window_handler.cc",
     "full_restore/arc_window_handler.h",
     "full_restore/arc_window_utils.cc",
@@ -4039,6 +4041,7 @@
     "input_method/emoji_suggester_unittest.cc",
     "input_method/fake_suggestion_handler.cc",
     "input_method/fake_suggestion_handler.h",
+    "input_method/grammar_manager_unittest.cc",
     "input_method/grammar_service_client_unittest.cc",
     "input_method/input_method_configuration_unittest.cc",
     "input_method/input_method_engine_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/echo_private_api.cc b/chrome/browser/chromeos/extensions/echo_private_api.cc
index 83efc4a..b3912a1 100644
--- a/chrome/browser/chromeos/extensions/echo_private_api.cc
+++ b/chrome/browser/chromeos/extensions/echo_private_api.cc
@@ -100,7 +100,8 @@
 
   PrefService* local_state = g_browser_process->local_state();
   DictionaryPrefUpdate offer_update(local_state, prefs::kEchoCheckedOffers);
-  offer_update->SetWithoutPathExpansion("echo." + service_id, std::move(dict));
+  offer_update->SetKey("echo." + service_id,
+                       base::Value::FromUniquePtrValue(std::move(dict)));
   return RespondNow(NoArguments());
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
index 5e5ef501..36f3a42 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -1282,7 +1282,7 @@
 
   std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
   for (const auto& hash : hashes) {
-    result->SetWithoutPathExpansion(hash, std::make_unique<base::ListValue>());
+    result->SetKey(hash, base::ListValue());
   }
 
   for (const auto& hashAndPath : search_results) {
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index d3585b8..33b213c 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -398,8 +398,7 @@
                                         prefs::kDefaultTasksByMimeType);
     for (std::set<std::string>::const_iterator iter = mime_types.begin();
         iter != mime_types.end(); ++iter) {
-      mime_type_pref->SetWithoutPathExpansion(
-          *iter, std::make_unique<base::Value>(task_id));
+      mime_type_pref->SetKey(*iter, base::Value(task_id));
     }
   }
 
@@ -410,8 +409,7 @@
         iter != suffixes.end(); ++iter) {
       // Suffixes are case insensitive.
       std::string lower_suffix = base::ToLowerASCII(*iter);
-      mime_type_pref->SetWithoutPathExpansion(
-          lower_suffix, std::make_unique<base::Value>(task_id));
+      mime_type_pref->SetKey(lower_suffix, base::Value(task_id));
     }
   }
 }
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc
index 8c8acd7b..5345dab7 100644
--- a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc
+++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.cc
@@ -6,14 +6,20 @@
 
 #include "ash/wm/desks/desks_util.h"
 #include "chrome/browser/chromeos/full_restore/arc_ghost_window_delegate.h"
+#include "chrome/browser/chromeos/full_restore/arc_ghost_window_view.h"
 #include "chrome/browser/chromeos/full_restore/arc_window_utils.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "components/exo/buffer.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "ui/aura/env.h"
-#include "ui/views/background.h"
 #include "ui/views/window/caption_button_types.h"
 
+namespace {
+
+constexpr int kDiameter = 24;
+
+}  // namespace
+
 namespace chromeos {
 namespace full_restore {
 
@@ -26,12 +32,10 @@
     absl::optional<gfx::Size> maximum_size,
     absl::optional<gfx::Size> minimum_size,
     absl::optional<uint32_t> color,
-    std::unique_ptr<views::View> content,
     base::RepeatingClosure close_callback) {
   absl::optional<double> scale_factor = GetDisplayScaleFactor(display_id);
   DCHECK(scale_factor.has_value());
 
-  // Set throbber color by |color_utils::GetColorWithMaxContrast(color)|.
   uint32_t theme_color = color.has_value() ? color.value() : SK_ColorWHITE;
 
   // TODO(sstan): Handle the desk container from full_restore data.
@@ -63,15 +67,9 @@
       1 << views::CAPTION_BUTTON_ICON_BACK |
       1 << views::CAPTION_BUTTON_ICON_MENU;
   shell_surface->SetFrameButtons(kAllButtonMask, kAllButtonMask);
-
-  content->SetBackground(views::CreateSolidBackground(theme_color));
   shell_surface->OnSetFrameColors(theme_color, theme_color);
 
-  // Apply ghost window content view.
-  exo::ShellSurfaceBase::OverlayParams overlay_params(std::move(content));
-  overlay_params.translucent = true;
-  overlay_params.overlaps_frame = false;
-  shell_surface->AddOverlay(std::move(overlay_params));
+  shell_surface->InitContentOverlay(app_id, theme_color);
 
   // Relayout overlay.
   shell_surface->controller_surface()->Commit();
@@ -112,5 +110,14 @@
   return controller_surface_.get();
 }
 
+void ArcGhostWindowShellSurface::InitContentOverlay(const std::string& app_id,
+                                                    uint32_t theme_color) {
+  exo::ShellSurfaceBase::OverlayParams overlay_params(
+      std::make_unique<ArcGhostWindowView>(kDiameter, app_id, theme_color));
+  overlay_params.translucent = true;
+  overlay_params.overlaps_frame = false;
+  AddOverlay(std::move(overlay_params));
+}
+
 }  // namespace full_restore
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.h b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.h
index 12cf4757..5caa021 100644
--- a/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.h
+++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_shell_surface.h
@@ -9,11 +9,6 @@
 
 #include "components/exo/client_controlled_shell_surface.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/views/view.h"
-
-namespace views {
-class View;
-}
 
 namespace chromeos {
 namespace full_restore {
@@ -29,7 +24,6 @@
     absl::optional<gfx::Size> maximum_size,
     absl::optional<gfx::Size> minimum_size,
     absl::optional<uint32_t> color,
-    std::unique_ptr<views::View> content,
     base::RepeatingClosure close_callback);
 
 // ArcGhostWindowShellSurface class is a shell surface which controlled its
@@ -44,6 +38,8 @@
       delete;
   ~ArcGhostWindowShellSurface() override;
 
+  void InitContentOverlay(const std::string& app_id, uint32_t theme_color);
+
   exo::Surface* controller_surface();
 
  private:
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_view.cc b/chrome/browser/chromeos/full_restore/arc_ghost_window_view.cc
new file mode 100644
index 0000000..9bcbbf4
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_view.cc
@@ -0,0 +1,109 @@
+// 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/chromeos/full_restore/arc_ghost_window_view.h"
+
+#include "ash/public/cpp/app_list/app_list_config.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_chromeos.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/chromeos/full_restore/arc_window_handler.h"
+#include "chrome/common/chrome_features.h"
+#include "components/services/app_service/public/mojom/types.mojom-forward.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/paint_throbber.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+
+namespace {
+
+class Throbber : public views::View {
+ public:
+  explicit Throbber(uint32_t color) : color_(color) {
+    start_time_ = base::TimeTicks::Now();
+    timer_.Start(
+        FROM_HERE, base::TimeDelta::FromMilliseconds(30),
+        base::BindRepeating(&Throbber::SchedulePaint, base::Unretained(this)));
+    SchedulePaint();  // paint right away
+  }
+  Throbber(const Throbber&) = delete;
+  Throbber operator=(const Throbber&) = delete;
+  ~Throbber() override { timer_.Stop(); }
+
+  void OnPaint(gfx::Canvas* canvas) override {
+    base::TimeDelta elapsed_time = base::TimeTicks::Now() - start_time_;
+    gfx::PaintThrobberSpinning(canvas, GetContentsBounds(), color_,
+                               elapsed_time);
+  }
+
+ private:
+  uint32_t color_;              // Throbber color.
+  base::TimeTicks start_time_;  // Time when Start was called.
+  base::RepeatingTimer timer_;  // Used to schedule Run calls.
+};
+
+}  // namespace
+
+namespace chromeos {
+namespace full_restore {
+
+ArcGhostWindowView::ArcGhostWindowView(int throbber_diameter,
+                                       const std::string& app_id,
+                                       uint32_t theme_color) {
+  InitLayout(theme_color, throbber_diameter);
+  LoadIcon(app_id);
+}
+
+ArcGhostWindowView::~ArcGhostWindowView() = default;
+
+void ArcGhostWindowView::InitLayout(uint32_t theme_color, int diameter) {
+  SetBackground(views::CreateSolidBackground(theme_color));
+  views::BoxLayout* layout =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kVertical));
+  layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kCenter);
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
+  layout->set_between_child_spacing(
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_RELATED_CONTROL_HORIZONTAL));
+
+  icon_view_ = AddChildView(std::make_unique<views::ImageView>());
+
+  auto* throbber = AddChildView(std::make_unique<Throbber>(
+      color_utils::GetColorWithMaxContrast(theme_color)));
+  throbber->SetPreferredSize({diameter, diameter});
+}
+
+void ArcGhostWindowView::LoadIcon(const std::string& app_id) {
+  Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByAccountId(
+      user_manager::UserManager::Get()->GetPrimaryUser()->GetAccountId());
+  DCHECK(profile);
+
+  auto icon_type =
+      (base::FeatureList::IsEnabled(features::kAppServiceAdaptiveIcon))
+          ? apps::mojom::IconType::kStandard
+          : apps::mojom::IconType::kUncompressed;
+
+  DCHECK(
+      apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile));
+  apps::AppServiceProxyFactory::GetForProfile(profile)->LoadIcon(
+      apps::mojom::AppType::kArc, app_id, icon_type,
+      ash::SharedAppListConfig::instance().default_grid_icon_dimension(),
+      /*allow_placeholder_icon=*/false,
+      base::BindOnce(&ArcGhostWindowView::OnIconLoaded,
+                     weak_ptr_factory_.GetWeakPtr(), icon_type));
+}
+
+void ArcGhostWindowView::OnIconLoaded(apps::mojom::IconType icon_type,
+                                      apps::mojom::IconValuePtr icon_value) {
+  if (icon_type != icon_value->icon_type)
+    return;
+  icon_view_->SetImage(icon_value->uncompressed);
+}
+
+}  // namespace full_restore
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/arc_ghost_window_view.h b/chrome/browser/chromeos/full_restore/arc_ghost_window_view.h
new file mode 100644
index 0000000..97fddbc
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/arc_ghost_window_view.h
@@ -0,0 +1,46 @@
+// 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_CHROMEOS_FULL_RESTORE_ARC_GHOST_WINDOW_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_FULL_RESTORE_ARC_GHOST_WINDOW_VIEW_H_
+
+#include "base/memory/weak_ptr.h"
+#include "components/services/app_service/public/mojom/app_service.mojom.h"
+#include "ui/views/view.h"
+
+namespace views {
+class ImageView;
+}
+
+namespace chromeos {
+namespace full_restore {
+
+// The view of ARC ghost window content. It shows the icon of app and a
+// throbber. It is used on ARC ghost window shell surface overlay, so it will
+// be destroyed after actual ARC task window launched.
+class ArcGhostWindowView : public views::View {
+ public:
+  explicit ArcGhostWindowView(int throbber_diameter,
+                              const std::string& app_id,
+                              uint32_t theme_color);
+  ArcGhostWindowView(const ArcGhostWindowView&) = delete;
+  ArcGhostWindowView operator=(const ArcGhostWindowView&) = delete;
+  ~ArcGhostWindowView() override;
+
+ private:
+  void InitLayout(uint32_t theme_color, int diameter);
+
+  void LoadIcon(const std::string& app_id);
+  void OnIconLoaded(apps::mojom::IconType icon_type,
+                    apps::mojom::IconValuePtr icon_value);
+
+  views::ImageView* icon_view_;
+
+  base::WeakPtrFactory<ArcGhostWindowView> weak_ptr_factory_{this};
+};
+
+}  // namespace full_restore
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FULL_RESTORE_ARC_GHOST_WINDOW_VIEW_H_
diff --git a/chrome/browser/chromeos/full_restore/arc_window_handler.cc b/chrome/browser/chromeos/full_restore/arc_window_handler.cc
index 75207d39..cabd3353 100644
--- a/chrome/browser/chromeos/full_restore/arc_window_handler.cc
+++ b/chrome/browser/chromeos/full_restore/arc_window_handler.cc
@@ -9,33 +9,6 @@
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/wm_helper.h"
 #include "components/full_restore/app_restore_data.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/controls/throbber.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/view.h"
-
-namespace {
-
-constexpr int kDiameter = 24;
-
-std::unique_ptr<views::View> GetGhostWindowContent() {
-  auto container = std::make_unique<views::View>();
-
-  auto* throbber_layout =
-      container->SetLayoutManager(std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kHorizontal));
-  throbber_layout->set_main_axis_alignment(
-      views::BoxLayout::MainAxisAlignment::kCenter);
-  throbber_layout->set_cross_axis_alignment(
-      views::BoxLayout::CrossAxisAlignment::kCenter);
-
-  auto* throbber = container->AddChildView(std::make_unique<views::Throbber>());
-  throbber->SetPreferredSize({kDiameter, kDiameter});
-  throbber->Start();
-  return container;
-}
-
-}  // namespace
 
 namespace chromeos {
 namespace full_restore {
@@ -80,7 +53,6 @@
           this, app_id, session_id, restore_data->display_id.value(),
           restore_data->current_bounds.value(), restore_data->maximum_size,
           restore_data->minimum_size, restore_data->status_bar_color,
-          GetGhostWindowContent(),
           base::BindRepeating(&ArcWindowHandler::CloseWindow,
                               weak_ptr_factory_.GetWeakPtr(), session_id)));
 }
diff --git a/chrome/browser/chromeos/input_method/grammar_manager.cc b/chrome/browser/chromeos/input_method/grammar_manager.cc
index 838a0fc..2dbd9970 100644
--- a/chrome/browser/chromeos/input_method/grammar_manager.cc
+++ b/chrome/browser/chromeos/input_method/grammar_manager.cc
@@ -19,7 +19,10 @@
 
 }  // namespace
 
-GrammarManager::GrammarManager() {}
+GrammarManager::GrammarManager(
+    Profile* profile,
+    std::unique_ptr<GrammarServiceClient> grammar_client)
+    : profile_(profile), grammar_client_(std::move(grammar_client)) {}
 
 GrammarManager::~GrammarManager() = default;
 
@@ -59,8 +62,31 @@
     return;
   }
 
-  // TODO(crbug/1132699): implement this method.
-  NOTIMPLEMENTED_LOG_ONCE();
+  ui::IMEInputContextHandlerInterface* input_context =
+      ui::IMEBridge::Get()->GetInputContextHandler();
+  if (!input_context)
+    return;
+
+  input_context->ClearGrammarFragments(gfx::Range(0, text.size()));
+
+  grammar_client_->RequestTextCheck(
+      profile_, text,
+      base::BindOnce(&GrammarManager::OnGrammarCheckDone,
+                     base::Unretained(this), text));
+}
+
+void GrammarManager::OnGrammarCheckDone(
+    const std::u16string& text,
+    bool success,
+    const std::vector<ui::GrammarFragment>& results) const {
+  if (!success || text != last_text_ || results.empty())
+    return;
+  ui::IMEInputContextHandlerInterface* input_context =
+      ui::IMEBridge::Get()->GetInputContextHandler();
+  if (!input_context)
+    return;
+
+  input_context->AddGrammarFragments(results);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/grammar_manager.h b/chrome/browser/chromeos/input_method/grammar_manager.h
index 573a9be..183dde2d 100644
--- a/chrome/browser/chromeos/input_method/grammar_manager.h
+++ b/chrome/browser/chromeos/input_method/grammar_manager.h
@@ -8,6 +8,8 @@
 #include <string>
 
 #include "base/timer/timer.h"
+#include "chrome/browser/chromeos/input_method/grammar_service_client.h"
+#include "chrome/browser/profiles/profile.h"
 #include "ui/events/event.h"
 
 namespace chromeos {
@@ -17,7 +19,8 @@
 // accept or dismiss the suggestions.
 class GrammarManager {
  public:
-  GrammarManager();
+  explicit GrammarManager(Profile* profile,
+                          std::unique_ptr<GrammarServiceClient> grammar_client);
   GrammarManager(const GrammarManager&) = delete;
   GrammarManager& operator=(const GrammarManager&) = delete;
   ~GrammarManager();
@@ -41,6 +44,13 @@
  private:
   void Check(const std::u16string& text);
 
+  void OnGrammarCheckDone(
+      const std::u16string& text,
+      bool success,
+      const std::vector<ui::GrammarFragment>& results) const;
+
+  Profile* profile_;
+  std::unique_ptr<GrammarServiceClient> grammar_client_;
   int context_id_ = 0;
   std::u16string last_text_;
   base::OneShotTimer delay_timer_;
diff --git a/chrome/browser/chromeos/input_method/grammar_manager_unittest.cc b/chrome/browser/chromeos/input_method/grammar_manager_unittest.cc
new file mode 100644
index 0000000..2924412
--- /dev/null
+++ b/chrome/browser/chromeos/input_method/grammar_manager_unittest.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 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/chromeos/input_method/grammar_manager.h"
+
+#include "chrome/browser/chromeos/input_method/grammar_service_client.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
+#include "components/spellcheck/common/spellcheck_result.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/chromeos/ime_bridge.h"
+#include "ui/base/ime/chromeos/mock_ime_input_context_handler.h"
+
+namespace chromeos {
+namespace {
+
+class TestGrammarServiceClient : public GrammarServiceClient {
+ public:
+  TestGrammarServiceClient() {}
+  ~TestGrammarServiceClient() override = default;
+
+  bool RequestTextCheck(Profile* profile,
+                        const std::u16string& text,
+                        TextCheckCompleteCallback callback) const override {
+    std::vector<ui::GrammarFragment> grammar_results;
+    for (int i = 0; i < text.size(); i++) {
+      if (text.substr(i, 5) == u"error") {
+        grammar_results.emplace_back(gfx::Range(i, i + 5), "correct");
+      }
+    }
+    std::move(callback).Run(true, grammar_results);
+    return true;
+  }
+};
+
+class GrammarManagerTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    profile_ = std::make_unique<TestingProfile>();
+    machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
+        &fake_service_connection_);
+    machine_learning::ServiceConnection::GetInstance()->Initialize();
+  }
+
+  content::BrowserTaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+  std::unique_ptr<TestingProfile> profile_;
+  machine_learning::FakeServiceConnectionImpl fake_service_connection_;
+};
+
+TEST_F(GrammarManagerTest, HandlesSingleGrammarCheckResult) {
+  ui::IMEBridge::Initialize();
+  ui::MockIMEInputContextHandler mock_ime_input_context_handler;
+  ui::IMEBridge::Get()->SetInputContextHandler(&mock_ime_input_context_handler);
+
+  GrammarManager manager(profile_.get(),
+                         std::make_unique<TestGrammarServiceClient>());
+
+  manager.OnFocus(1);
+  manager.OnSurroundingTextChanged(u"There is error.", 0, 0);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+
+  auto grammar_fragments =
+      mock_ime_input_context_handler.get_grammar_fragments();
+  EXPECT_EQ(grammar_fragments.size(), 1);
+  EXPECT_EQ(grammar_fragments[0].range, gfx::Range(9, 14));
+  EXPECT_EQ(grammar_fragments[0].suggestion, "correct");
+}
+
+TEST_F(GrammarManagerTest, HandlesMultipleGrammarCheckResults) {
+  ui::IMEBridge::Initialize();
+  ui::MockIMEInputContextHandler mock_ime_input_context_handler;
+  ui::IMEBridge::Get()->SetInputContextHandler(&mock_ime_input_context_handler);
+
+  GrammarManager manager(profile_.get(),
+                         std::make_unique<TestGrammarServiceClient>());
+
+  manager.OnFocus(1);
+  manager.OnSurroundingTextChanged(u"There is error error.", 0, 0);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+
+  auto grammar_fragments =
+      mock_ime_input_context_handler.get_grammar_fragments();
+  EXPECT_EQ(grammar_fragments.size(), 2);
+  EXPECT_EQ(grammar_fragments[0].range, gfx::Range(9, 14));
+  EXPECT_EQ(grammar_fragments[0].suggestion, "correct");
+  EXPECT_EQ(grammar_fragments[1].range, gfx::Range(15, 20));
+  EXPECT_EQ(grammar_fragments[0].suggestion, "correct");
+}
+
+TEST_F(GrammarManagerTest, ClearsPreviousMarkersUponGettingNewResults) {
+  ui::IMEBridge::Initialize();
+  ui::MockIMEInputContextHandler mock_ime_input_context_handler;
+  ui::IMEBridge::Get()->SetInputContextHandler(&mock_ime_input_context_handler);
+
+  GrammarManager manager(profile_.get(),
+                         std::make_unique<TestGrammarServiceClient>());
+
+  manager.OnFocus(1);
+  manager.OnSurroundingTextChanged(u"There is error.", 0, 0);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+
+  auto grammar_fragments =
+      mock_ime_input_context_handler.get_grammar_fragments();
+  EXPECT_EQ(grammar_fragments.size(), 1);
+  EXPECT_EQ(grammar_fragments[0].range, gfx::Range(9, 14));
+  EXPECT_EQ(grammar_fragments[0].suggestion, "correct");
+
+  manager.OnSurroundingTextChanged(u"There is a new error.", 0, 0);
+  task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1000));
+
+  auto updated_grammar_fragments =
+      mock_ime_input_context_handler.get_grammar_fragments();
+  EXPECT_EQ(updated_grammar_fragments.size(), 1);
+  EXPECT_EQ(updated_grammar_fragments[0].range, gfx::Range(15, 20));
+  EXPECT_EQ(updated_grammar_fragments[0].suggestion, "correct");
+}
+
+}  // namespace
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/grammar_service_client.cc b/chrome/browser/chromeos/input_method/grammar_service_client.cc
index b5f5197..96204a3 100644
--- a/chrome/browser/chromeos/input_method/grammar_service_client.cc
+++ b/chrome/browser/chromeos/input_method/grammar_service_client.cc
@@ -10,8 +10,8 @@
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
 #include "components/prefs/pref_service.h"
 #include "components/spellcheck/browser/pref_names.h"
-#include "components/spellcheck/common/spellcheck_result.h"
 #include "components/user_prefs/user_prefs.h"
+#include "ui/gfx/range/range.h"
 
 namespace chromeos {
 namespace {
@@ -121,7 +121,7 @@
       !result->candidates.empty()) {
     const auto& top_candidate = result->candidates.front();
     if (!top_candidate->text.empty() && !top_candidate->fragments.empty()) {
-      std::vector<SpellCheckResult> grammar_results;
+      std::vector<ui::GrammarFragment> grammar_results;
       for (const auto& fragment : top_candidate->fragments) {
         uint32_t start;
         uint32_t end;
@@ -138,9 +138,8 @@
           // Compute the offsets in string16.
           std::vector<size_t> offsets = {start, end};
           base::UTF8ToUTF16AndAdjustOffsets(query_text, &offsets);
-          grammar_results.emplace_back(
-              SpellCheckResult::GRAMMAR, offsets[0], offsets[1] - offsets[0],
-              base::UTF8ToUTF16(fragment->replacement));
+          grammar_results.emplace_back(gfx::Range(offsets[0], offsets[1]),
+                                       fragment->replacement);
         }
       }
       std::move(callback).Run(true, grammar_results);
diff --git a/chrome/browser/chromeos/input_method/grammar_service_client.h b/chrome/browser/chromeos/input_method/grammar_service_client.h
index 02fc63c2..9257592 100644
--- a/chrome/browser/chromeos/input_method/grammar_service_client.h
+++ b/chrome/browser/chromeos/input_method/grammar_service_client.h
@@ -12,8 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/services/machine_learning/public/mojom/grammar_checker.mojom.h"
 #include "mojo/public/cpp/bindings/remote.h"
-
-struct SpellCheckResult;
+#include "ui/base/ime/grammar_fragment.h"
 
 namespace chromeos {
 
@@ -47,17 +46,17 @@
 class GrammarServiceClient {
  public:
   GrammarServiceClient();
-  ~GrammarServiceClient();
+  virtual ~GrammarServiceClient();
 
   using TextCheckCompleteCallback = base::OnceCallback<void(
       bool /* success */,
-      const std::vector<SpellCheckResult>& /* results */)>;
+      const std::vector<ui::GrammarFragment>& /* results */)>;
 
   // Sends grammar check request to ML service, parses the reponse
   // and calls a provided callback method.
-  bool RequestTextCheck(Profile* profile,
-                        const std::u16string& text,
-                        TextCheckCompleteCallback callback) const;
+  virtual bool RequestTextCheck(Profile* profile,
+                                const std::u16string& text,
+                                TextCheckCompleteCallback callback) const;
 
  private:
   // Parse the result returned from grammar check service.
diff --git a/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc b/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
index 3ca1047..d359e4aa 100644
--- a/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
+++ b/chrome/browser/chromeos/input_method/grammar_service_client_unittest.cc
@@ -14,9 +14,10 @@
 #include "chromeos/services/machine_learning/public/mojom/grammar_checker.mojom.h"
 #include "components/prefs/pref_service.h"
 #include "components/spellcheck/browser/pref_names.h"
-#include "components/spellcheck/common/spellcheck_result.h"
 #include "content/public/test/browser_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ime/grammar_fragment.h"
+#include "ui/gfx/range/range.h"
 
 namespace chromeos {
 namespace {
@@ -46,7 +47,7 @@
   client.RequestTextCheck(
       profile.get(), u"cat",
       base::BindOnce(
-          [](bool success, const std::vector<SpellCheckResult>& results) {
+          [](bool success, const std::vector<ui::GrammarFragment>& results) {
             EXPECT_FALSE(success);
             EXPECT_TRUE(results.empty());
           }));
@@ -88,14 +89,11 @@
   client.RequestTextCheck(
       profile.get(), u"fake input",
       base::BindOnce(
-          [](bool success, const std::vector<SpellCheckResult>& results) {
+          [](bool success, const std::vector<ui::GrammarFragment>& results) {
             EXPECT_TRUE(success);
             ASSERT_EQ(results.size(), 1U);
-            EXPECT_EQ(results[0].decoration, SpellCheckResult::GRAMMAR);
-            EXPECT_EQ(results[0].location, 3);
-            EXPECT_EQ(results[0].length, 5);
-            ASSERT_EQ(results[0].replacements.size(), 1U);
-            EXPECT_EQ(results[0].replacements[0], u"fake replacement");
+            EXPECT_EQ(results[0].range, gfx::Range(3, 8));
+            EXPECT_EQ(results[0].suggestion, "fake replacement");
           }));
 
   base::RunLoop().RunUntilIdle();
@@ -141,16 +139,13 @@
   client.RequestTextCheck(
       profile.get(), long_text,
       base::BindOnce(
-          [](bool success, const std::vector<SpellCheckResult>& results) {
+          [](bool success, const std::vector<ui::GrammarFragment>& results) {
             EXPECT_TRUE(success);
             ASSERT_EQ(results.size(), 1U);
-            EXPECT_EQ(results[0].decoration, SpellCheckResult::GRAMMAR);
             // The fake grammar check result is set to return offset=3, so here
             // getting the location as 203 verifies the trimming.
-            EXPECT_EQ(results[0].location, 203);
-            EXPECT_EQ(results[0].length, 5);
-            ASSERT_EQ(results[0].replacements.size(), 1U);
-            EXPECT_EQ(results[0].replacements[0], u"fake replacement");
+            EXPECT_EQ(results[0].range, gfx::Range(203, 208));
+            EXPECT_EQ(results[0].suggestion, "fake replacement");
           }));
 
   base::RunLoop().RunUntilIdle();
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 6554862..c1ca86d3 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_offset_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/input_method/autocorrect_manager.h"
+#include "chrome/browser/chromeos/input_method/grammar_service_client.h"
 #include "chrome/browser/chromeos/input_method/suggestions_service_client.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
@@ -188,7 +189,9 @@
       std::make_unique<chromeos::NativeInputMethodEngine::ImeObserver>(
           profile->GetPrefs(), std::move(observer),
           std::move(assistive_suggester), std::move(autocorrect_manager),
-          std::move(suggestions_collector), std::make_unique<GrammarManager>());
+          std::move(suggestions_collector),
+          std::make_unique<GrammarManager>(
+              profile, std::make_unique<GrammarServiceClient>()));
   InputMethodEngine::Initialize(std::move(native_observer), extension_id,
                                 profile);
 }
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 c941473..427124e0 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
@@ -13,6 +13,7 @@
 #include "chrome/test/base/testing_profile.h"
 #include "chromeos/services/ime/mock_input_channel.h"
 #include "chromeos/services/ime/public/mojom/input_engine.mojom.h"
+#include "chromeos/services/machine_learning/public/cpp/fake_service_connection.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/web_contents.h"
@@ -119,6 +120,10 @@
     // Needed by NativeInputMethodEngine for the virtual keyboard.
     keyboard_controller_client_test_helper_ =
         ChromeKeyboardControllerClientTestHelper::InitializeWithFake();
+
+    machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
+        &fake_service_connection_);
+    machine_learning::ServiceConnection::GetInstance()->Initialize();
   }
 
  private:
@@ -126,6 +131,7 @@
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ChromeKeyboardControllerClientTestHelper>
       keyboard_controller_client_test_helper_;
+  machine_learning::FakeServiceConnectionImpl fake_service_connection_;
 };
 
 TEST_F(NativeInputMethodEngineTest, DoesNotLaunchImeServiceIfAutocorrectIsOff) {
@@ -379,6 +385,10 @@
     // Needed by NativeInputMethodEngine for the virtual keyboard.
     keyboard_controller_client_test_helper_ =
         ChromeKeyboardControllerClientTestHelper::InitializeWithFake();
+
+    machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
+        &fake_service_connection_);
+    machine_learning::ServiceConnection::GetInstance()->Initialize();
   }
 
   std::unique_ptr<content::BrowserContext> CreateBrowserContext() override {
@@ -389,6 +399,7 @@
   base::test::ScopedFeatureList feature_list_;
   std::unique_ptr<ChromeKeyboardControllerClientTestHelper>
       keyboard_controller_client_test_helper_;
+  machine_learning::FakeServiceConnectionImpl fake_service_connection_;
 };
 
 TEST_F(NativeInputMethodEngineWithRenderViewHostTest, RecordUkmAddsUkmEntry) {
diff --git a/chrome/browser/chromeos/input_method/suggestions_service_client.cc b/chrome/browser/chromeos/input_method/suggestions_service_client.cc
index 4ea44c27..81ae477 100644
--- a/chrome/browser/chromeos/input_method/suggestions_service_client.cc
+++ b/chrome/browser/chromeos/input_method/suggestions_service_client.cc
@@ -5,8 +5,8 @@
 #include "chrome/browser/chromeos/input_method/suggestions_service_client.h"
 
 #include "base/bind.h"
+#include "base/optional.h"
 #include "chromeos/services/machine_learning/public/cpp/service_connection.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
 
 namespace chromeos {
 namespace {
@@ -19,19 +19,27 @@
 using ::chromeos::machine_learning::mojom::TextSuggesterResultPtr;
 using ::chromeos::machine_learning::mojom::TextSuggestionCandidatePtr;
 
-absl::optional<TextSuggestion> ToTextSuggestion(
-    const TextSuggestionCandidatePtr& candidate) {
+machine_learning::mojom::TextSuggestionMode ToTextSuggestionModeMojom(
+    TextSuggestionMode suggestion_mode) {
+  switch (suggestion_mode) {
+    case TextSuggestionMode::kCompletion:
+      return machine_learning::mojom::TextSuggestionMode::kCompletion;
+    case TextSuggestionMode::kPrediction:
+      return machine_learning::mojom::TextSuggestionMode::kPrediction;
+  }
+}
+
+base::Optional<TextSuggestion> ToTextSuggestion(
+    const TextSuggestionCandidatePtr& candidate,
+    const TextSuggestionMode& suggestion_mode) {
   if (!candidate->is_multi_word()) {
     // TODO(crbug/1146266): Handle emoji suggestions
     return absl::nullopt;
   }
 
-  return TextSuggestion{
-      // TODO(crbug/1146266): Introduce suggestion mode to suggestion service
-      // interface. For the moment, everything is a completion.
-      .mode = TextSuggestionMode::kCompletion,
-      .type = TextSuggestionType::kMultiWord,
-      .text = candidate->get_multi_word()->text};
+  return TextSuggestion{.mode = suggestion_mode,
+                        .type = TextSuggestionType::kMultiWord,
+                        .text = candidate->get_multi_word()->text};
 }
 
 }  // namespace
@@ -58,16 +66,14 @@
     const ime::TextSuggestionMode& suggestion_mode,
     const std::vector<ime::TextCompletionCandidate>& completion_candidates,
     RequestSuggestionsCallback callback) {
-  if (!IsAvailable() ||
-      suggestion_mode != ime::TextSuggestionMode::kCompletion) {
-    // TODO(crbug/1146266): Support prediction requests when suggestion mojo
-    // service introduces suggestion_mode to interface.
+  if (!IsAvailable()) {
     std::move(callback).Run({});
     return;
   }
 
   auto query = TextSuggesterQuery::New();
   query->text = preceding_text;
+  query->suggestion_mode = ToTextSuggestionModeMojom(suggestion_mode);
 
   for (const auto& candidate : completion_candidates) {
     auto next_word_candidate = NextWordCompletionCandidate::New();
@@ -79,16 +85,19 @@
   text_suggester_->Suggest(
       std::move(query),
       base::BindOnce(&SuggestionsServiceClient::OnSuggestionsReturned,
-                     base::Unretained(this), std::move(callback)));
+                     base::Unretained(this), std::move(callback),
+                     suggestion_mode));
 }
 
 void SuggestionsServiceClient::OnSuggestionsReturned(
     RequestSuggestionsCallback callback,
+    TextSuggestionMode suggestion_mode_requested,
     chromeos::machine_learning::mojom::TextSuggesterResultPtr result) {
   std::vector<TextSuggestion> suggestions;
 
   for (const auto& candidate : result->candidates) {
-    auto suggestion = ToTextSuggestion(std::move(candidate));
+    auto suggestion =
+        ToTextSuggestion(std::move(candidate), suggestion_mode_requested);
     if (suggestion) {
       // Drop any unknown suggestions
       suggestions.push_back(suggestion.value());
diff --git a/chrome/browser/chromeos/input_method/suggestions_service_client.h b/chrome/browser/chromeos/input_method/suggestions_service_client.h
index d6011ee..5cff9aa 100644
--- a/chrome/browser/chromeos/input_method/suggestions_service_client.h
+++ b/chrome/browser/chromeos/input_method/suggestions_service_client.h
@@ -33,6 +33,7 @@
   // Called when results are returned from the suggestions service
   void OnSuggestionsReturned(
       RequestSuggestionsCallback callback,
+      ime::TextSuggestionMode suggestion_mode_requested,
       chromeos::machine_learning::mojom::TextSuggesterResultPtr result);
 
   mojo::Remote<chromeos::machine_learning::mojom::TextSuggester>
diff --git a/chrome/browser/chromeos/input_method/suggestions_service_client_unittest.cc b/chrome/browser/chromeos/input_method/suggestions_service_client_unittest.cc
index 9aa1d9af..125d459 100644
--- a/chrome/browser/chromeos/input_method/suggestions_service_client_unittest.cc
+++ b/chrome/browser/chromeos/input_method/suggestions_service_client_unittest.cc
@@ -27,21 +27,29 @@
   content::BrowserTaskEnvironment task_environment_;
 };
 
-TEST_F(SuggestionsServiceClientTest, ReturnsResultsFromMojoService) {
+machine_learning::mojom::TextSuggesterResultPtr GenerateMultiWordResult(
+    std::string text,
+    float score) {
+  auto result = machine_learning::mojom::TextSuggesterResult::New();
+  result->status = machine_learning::mojom::TextSuggesterResult::Status::OK;
+  auto multi_word = machine_learning::mojom::MultiWordSuggestionCandidate::New(
+      /*text=*/text, /*normalized_score=*/score);
+  auto candidate = machine_learning::mojom::TextSuggestionCandidate::New();
+  candidate->set_multi_word(std::move(multi_word));
+  result->candidates.emplace_back(std::move(candidate));
+  return result;
+}
+
+TEST_F(SuggestionsServiceClientTest, ReturnsCompletionResultsFromMojoService) {
   machine_learning::FakeServiceConnectionImpl fake_service_connection;
   machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
       &fake_service_connection);
   machine_learning::ServiceConnection::GetInstance()->Initialize();
 
   // Construct fake output
-  auto result = machine_learning::mojom::TextSuggesterResult::New();
-  result->status = machine_learning::mojom::TextSuggesterResult::Status::OK;
-  auto multi_word = machine_learning::mojom::MultiWordSuggestionCandidate::New(
-      /*text=*/"hi there", /*normalized_score=*/0.5f);
-  auto candidate = machine_learning::mojom::TextSuggestionCandidate::New();
-  candidate->set_multi_word(std::move(multi_word));
-  result->candidates.emplace_back(std::move(candidate));
-  fake_service_connection.SetOutputTextSuggesterResult(result);
+  machine_learning::mojom::TextSuggesterResultPtr result =
+      GenerateMultiWordResult("hi there completion", 0.5f);
+  fake_service_connection.SetOutputTextSuggesterResult(std::move(result));
 
   SuggestionsServiceClient client;
   base::RunLoop().RunUntilIdle();
@@ -60,19 +68,24 @@
   std::vector<TextSuggestion> expected_results = {
       TextSuggestion{.mode = TextSuggestionMode::kCompletion,
                      .type = TextSuggestionType::kMultiWord,
-                     .text = "hi there"},
+                     .text = "hi there completion"},
   };
 
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(returned_results, expected_results);
 }
 
-TEST_F(SuggestionsServiceClientTest, DoesntRequestPredictionCandidates) {
+TEST_F(SuggestionsServiceClientTest, ReturnsPredictionResultsFromMojoService) {
   machine_learning::FakeServiceConnectionImpl fake_service_connection;
   machine_learning::ServiceConnection::UseFakeServiceConnectionForTesting(
       &fake_service_connection);
   machine_learning::ServiceConnection::GetInstance()->Initialize();
 
+  // Construct fake output
+  machine_learning::mojom::TextSuggesterResultPtr result =
+      GenerateMultiWordResult("hi there prediction", 0.5f);
+  fake_service_connection.SetOutputTextSuggesterResult(std::move(result));
+
   SuggestionsServiceClient client;
   base::RunLoop().RunUntilIdle();
 
@@ -87,8 +100,14 @@
             returned_results = results;
           }));
 
+  std::vector<TextSuggestion> expected_results = {
+      TextSuggestion{.mode = TextSuggestionMode::kPrediction,
+                     .type = TextSuggestionType::kMultiWord,
+                     .text = "hi there prediction"},
+  };
+
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(returned_results.empty());
+  EXPECT_EQ(returned_results, expected_results);
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc b/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc
index 03df4d31..cdd3eff 100644
--- a/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc
+++ b/chrome/browser/chromeos/platform_keys/key_permissions/arc_key_permissions_manager_delegate_unittest.cc
@@ -109,8 +109,8 @@
                                  base::Value(allowed));
 
     base::DictionaryValue policy_value;
-    policy_value.SetWithoutPathExpansion(package_name,
-                                         std::move(corporate_key_usage));
+    policy_value.SetKey(package_name, base::Value::FromUniquePtrValue(
+                                          std::move(corporate_key_usage)));
 
     policy::PolicyMap policy_map;
     policy_map.Set(policy::key::kKeyPermissions, policy::POLICY_LEVEL_MANDATORY,
diff --git a/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_pref_util.cc b/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_pref_util.cc
index f6501c9..8ba84ad2 100644
--- a/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_pref_util.cc
+++ b/chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_pref_util.cc
@@ -83,8 +83,8 @@
   auto new_pref_entry = std::make_unique<base::DictionaryValue>();
   new_pref_entry->SetKey(kPrefKeyUsage, base::Value(kPrefKeyUsageCorporate));
 
-  update->SetWithoutPathExpansion(public_key_spki_der_b64,
-                                  std::move(new_pref_entry));
+  update->SetKey(public_key_spki_der_b64,
+                 base::Value::FromUniquePtrValue(std::move(new_pref_entry)));
 }
 
 }  // namespace internal
diff --git a/chrome/browser/component_updater/first_party_sets_component_installer.cc b/chrome/browser/component_updater/first_party_sets_component_installer.cc
index ac7db03..d97bc9bb 100644
--- a/chrome/browser/component_updater/first_party_sets_component_installer.cc
+++ b/chrome/browser/component_updater/first_party_sets_component_installer.cc
@@ -185,8 +185,7 @@
           /*on_sets_ready=*/base::BindRepeating(
               [](const std ::string& raw_sets) {
                 VLOG(1) << "Received Sets: \"" << raw_sets << "\"";
-                content::GetNetworkService()->SetPreloadedFirstPartySets(
-                    raw_sets);
+                content::GetNetworkService()->SetFirstPartySets(raw_sets);
               })));
   installer->Register(cus, base::OnceClosure());
 }
diff --git a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
index 5066baf..8a539f9 100644
--- a/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_pref_provider_unittest.cc
@@ -163,11 +163,13 @@
   base::DictionaryValue plugins_data_pref;
   auto dict = std::make_unique<base::DictionaryValue>();
   constexpr char kFlagKey[] = "flashPreviouslyChanged";
-  plugins_data_pref.SetWithoutPathExpansion(kFlagKey, std::move(dict));
+  plugins_data_pref.SetKey(kFlagKey,
+                           base::Value::FromUniquePtrValue(std::move(dict)));
 
   auto data_for_pattern = std::make_unique<base::DictionaryValue>();
   data_for_pattern->SetInteger("setting", CONTENT_SETTING_ALLOW);
-  pref_data.SetWithoutPathExpansion(kPattern, std::move(data_for_pattern));
+  pref_data.SetKey(
+      kPattern, base::Value::FromUniquePtrValue(std::move(data_for_pattern)));
   prefs->Set(kFullscreenPrefPath, pref_data);
 #if !defined(OS_ANDROID)
   prefs->Set(kMouselockPrefPath, pref_data);
@@ -381,8 +383,7 @@
   {
     DictionaryPrefUpdate update(&prefs, info->pref_name());
     base::DictionaryValue* mutable_settings = update.Get();
-    mutable_settings->SetWithoutPathExpansion(
-        "www.example.com,*", std::make_unique<base::DictionaryValue>());
+    mutable_settings->SetKey("www.example.com,*", base::DictionaryValue());
   }
   EXPECT_TRUE(observer.notification_received());
 
diff --git a/chrome/browser/content_settings/host_content_settings_map_unittest.cc b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
index 8df1e0a..f8994f09 100644
--- a/chrome/browser/content_settings/host_content_settings_map_unittest.cc
+++ b/chrome/browser/content_settings/host_content_settings_map_unittest.cc
@@ -1095,8 +1095,9 @@
 
     auto dummy_payload = std::make_unique<base::DictionaryValue>();
     dummy_payload->SetInteger("setting", CONTENT_SETTING_ALLOW);
-    all_settings_dictionary->SetWithoutPathExpansion("[*.]\xC4\x87ira.com,*",
-                                                     std::move(dummy_payload));
+    all_settings_dictionary->SetKey(
+        "[*.]\xC4\x87ira.com,*",
+        base::Value::FromUniquePtrValue(std::move(dummy_payload)));
   }
 
   HostContentSettingsMapFactory::GetForProfile(&profile);
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
index acdffcf3..35f2af2 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
@@ -5,6 +5,7 @@
 #include <memory>
 #include <string>
 
+#include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
@@ -37,7 +38,7 @@
 class ProtocolHandlerChangeWaiter : public ProtocolHandlerRegistry::Observer {
  public:
   explicit ProtocolHandlerChangeWaiter(ProtocolHandlerRegistry* registry) {
-    registry_observer_.Add(registry);
+    registry_observation_.Observe(registry);
   }
   ProtocolHandlerChangeWaiter(const ProtocolHandlerChangeWaiter&) = delete;
   ProtocolHandlerChangeWaiter& operator=(const ProtocolHandlerChangeWaiter&) =
@@ -49,8 +50,9 @@
   void OnProtocolHandlerRegistryChanged() override { run_loop_.Quit(); }
 
  private:
-  ScopedObserver<ProtocolHandlerRegistry, ProtocolHandlerRegistry::Observer>
-      registry_observer_{this};
+  base::ScopedObservation<ProtocolHandlerRegistry,
+                          ProtocolHandlerRegistry::Observer>
+      registry_observation_{this};
   base::RunLoop run_loop_;
 };
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index 456ab10..88e88e1 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -12,7 +12,7 @@
 
 #include "base/bind.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
@@ -146,7 +146,7 @@
 class ProtocolHandlerChangeListener : public ProtocolHandlerRegistry::Observer {
  public:
   explicit ProtocolHandlerChangeListener(ProtocolHandlerRegistry* registry) {
-    registry_observer_.Add(registry);
+    registry_observation_.Observe(registry);
   }
   ~ProtocolHandlerChangeListener() override = default;
 
@@ -160,8 +160,9 @@
  private:
   int events_ = 0;
 
-  ScopedObserver<ProtocolHandlerRegistry, ProtocolHandlerRegistry::Observer>
-      registry_observer_{this};
+  base::ScopedObservation<ProtocolHandlerRegistry,
+                          ProtocolHandlerRegistry::Observer>
+      registry_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(ProtocolHandlerChangeListener);
 };
@@ -170,7 +171,7 @@
  public:
   explicit QueryProtocolHandlerOnChange(ProtocolHandlerRegistry* registry)
       : local_registry_(registry) {
-    registry_observer_.Add(registry);
+    registry_observation_.Observe(registry);
   }
 
   // ProtocolHandlerRegistry::Observer:
@@ -186,8 +187,9 @@
   ProtocolHandlerRegistry* local_registry_;
   bool called_ = false;
 
-  ScopedObserver<ProtocolHandlerRegistry, ProtocolHandlerRegistry::Observer>
-      registry_observer_{this};
+  base::ScopedObservation<ProtocolHandlerRegistry,
+                          ProtocolHandlerRegistry::Observer>
+      registry_observation_{this};
 
   DISALLOW_COPY_AND_ASSIGN(QueryProtocolHandlerOnChange);
 };
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index ab66df8d..03572b0 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -369,8 +369,7 @@
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kDevToolsFileSystemPaths);
   base::DictionaryValue* file_systems_paths_value = update.Get();
-  file_systems_paths_value->SetWithoutPathExpansion(
-      file_system_path, std::make_unique<base::Value>(type));
+  file_systems_paths_value->SetKey(file_system_path, base::Value(type));
 }
 
 void DevToolsFileHelper::FailedToAddFileSystem(const std::string& error) {
diff --git a/chrome/browser/download/android/java/res/DIR_METADATA b/chrome/browser/download/android/java/res/DIR_METADATA
index 51631587..7a2580a 100644
--- a/chrome/browser/download/android/java/res/DIR_METADATA
+++ b/chrome/browser/download/android/java/res/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "UI>Browser>Downloads"
-}
 os: ANDROID
diff --git a/chrome/browser/download/internal/DIR_METADATA b/chrome/browser/download/internal/DIR_METADATA
index f569985b..8ed74fda 100644
--- a/chrome/browser/download/internal/DIR_METADATA
+++ b/chrome/browser/download/internal/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Downloads"
-}
 team_email: "chrome-downloads@google.com"
diff --git a/chrome/browser/enterprise/reporting/DIR_METADATA b/chrome/browser/enterprise/reporting/DIR_METADATA
deleted file mode 100644
index f37723a..0000000
--- a/chrome/browser/enterprise/reporting/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Enterprise"
-}
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
index 60f68d4d..e69e650 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.cc
@@ -39,6 +39,12 @@
 constexpr char kWebAppWindow[] = "WEB_APP";
 constexpr char kSystemWebAppWindow[] = "SYSTEM_WEB_APP";
 
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+// Give up if crash_reporter hasn't finished in this long.
+constexpr base::TimeDelta kMaximumWaitForCrashReporter =
+    base::TimeDelta::FromMinutes(1);
+#endif
+
 // Sometimes, the stack trace will contain an error message as the first line,
 // which confuses the Crash server. This function deletes it if it is present.
 void RemoveErrorMessageFromStackTrace(const std::string& error_message,
@@ -81,7 +87,12 @@
 }  // namespace
 
 ChromeJsErrorReportProcessor::ChromeJsErrorReportProcessor()
-    : clock_(base::DefaultClock::GetInstance()) {}
+    :
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+      maximium_wait_for_crash_reporter_(kMaximumWaitForCrashReporter),
+#endif
+      clock_(base::DefaultClock::GetInstance()) {
+}
 ChromeJsErrorReportProcessor::~ChromeJsErrorReportProcessor() = default;
 
 // Returns the redacted, fixed-up error report if the user consented to have it
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor.h b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
index 006a85d6..ffbdcdb 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor.h
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor.h
@@ -21,6 +21,9 @@
 #include "components/crash/content/browser/error_reporting/js_error_report_processor.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 
+namespace base {
+class Process;
+}
 namespace content {
 class BrowserContext;
 }
@@ -62,6 +65,12 @@
   // on old kernels without memfd_create, so we don't get good unit test
   // coverage unless we force it.
   void set_force_non_memfd_for_test() { force_non_memfd_for_test_ = true; }
+
+  // Set the length of time we want for the crash_reporter (or the
+  // mock_crash_reporter) to finish.
+  void set_maximium_wait_for_crash_reporter_for_test(base::TimeDelta max_wait) {
+    maximium_wait_for_crash_reporter_ = max_wait;
+  }
 #endif
 
  protected:
@@ -156,9 +165,18 @@
       const absl::optional<std::string>& stack_trace);
 
   void SendReportViaCrashReporter(ParameterMap params,
-                                  absl::optional<std::string> stack_trace);
+                                  absl::optional<std::string> stack_trace,
+                                  base::ScopedClosureRunner callback_runner);
+  void WaitForCrashReporter(base::Process process,
+                            base::Time process_creation_time,
+                            base::ScopedClosureRunner file_cleanup,
+                            base::ScopedClosureRunner external_callback_runner);
 
   bool force_non_memfd_for_test_ = false;
+
+  // If crash_reporter isn't finished after this long, kill it and clean up
+  // anyways.
+  base::TimeDelta maximium_wait_for_crash_reporter_;
 #else
   // Turn the parameter key/value pairs into a list of parameters suitable for
   // being the query part of a URL. Does URL escaping and such.
diff --git a/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
index 3d1fa39e..17f4cef 100644
--- a/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
+++ b/chrome/browser/error_reporting/chrome_js_error_report_processor_chromeos.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 
+#include "base/bind_post_task.h"
 #include "base/callback_helpers.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
@@ -19,10 +20,12 @@
 #include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
-#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/error_reporting/constants.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 // Per the memfd_create man page, we need _GNU_SOURCE
@@ -84,6 +87,33 @@
 
 }  // namespace
 
+// Called after giving crash_reporter time to finish. If crash_reporter is
+// taking too long, kills it. Either way, triggers the callbacks once
+// crash_reporter is done.
+void ChromeJsErrorReportProcessor::WaitForCrashReporter(
+    base::Process process,
+    base::Time process_creation_time,
+    base::ScopedClosureRunner file_cleanup,
+    base::ScopedClosureRunner external_callback_runner) {
+  int return_code = 0;
+  bool process_done = process.WaitForExitWithTimeout(
+      base::TimeDelta::FromSeconds(0), &return_code);
+
+  if (process_done) {
+    if (return_code != 0) {
+      LOG(WARNING) << "crash_reporter subprocess failed with return value "
+                   << return_code
+                   << (return_code == -1 ? " or maybe crashed" : "");
+    }
+    return;
+  }
+
+  // Kill the stuck process to avoid zombies.
+  LOG(WARNING) << "crash_reporter failed to complete within "
+               << maximium_wait_for_crash_reporter_;
+  process.Terminate(0, false /*wait*/);
+}
+
 std::vector<std::string>
 ChromeJsErrorReportProcessor::GetCrashReporterArgvStart() {
   return {"/sbin/crash_reporter"};
@@ -113,7 +143,8 @@
 
 void ChromeJsErrorReportProcessor::SendReportViaCrashReporter(
     ParameterMap params,
-    absl::optional<std::string> stack_trace) {
+    absl::optional<std::string> stack_trace,
+    base::ScopedClosureRunner callback_runner) {
   base::ScopedClosureRunner cleanup;
   base::File output(GetMemfdOrTempFile(cleanup, force_non_memfd_for_test_));
   if (!output.IsValid()) {
@@ -147,26 +178,21 @@
     return;
   }
 
-  {
-    base::ScopedAllowBaseSyncPrimitives allow_wait_for_exit;
-    // Wait for crash_reporter to finish. We need to wait for it to finish
-    // before we delete the temporary files that may have been created in
-    // GetMemfdOrTempFile().
-    int return_code = 0;
-    constexpr base::TimeDelta kMaximumWait = base::TimeDelta::FromMinutes(1);
-    if (process.WaitForExitWithTimeout(kMaximumWait, &return_code)) {
-      if (return_code != 0) {
-        LOG(WARNING) << "crash_reporter subprocess failed with return value "
-                     << return_code
-                     << (return_code == -1 ? " or maybe crashed" : "");
-      }
-    } else {
-      // Kill the stuck process to avoid zombies.
-      LOG(WARNING) << "crash_reporter failed to complete within "
-                   << kMaximumWait;
-      process.Terminate(0, false /*wait*/);
-    }
-  }
+  // Wait for crash_reporter to finish. We need to wait for it to finish before
+  // we delete the temporary files that may have been created in
+  // GetMemfdOrTempFile(). (Also, it makes the unit tests much easier.)
+  // However, we can't just
+  // process.WaitForExitWithTimeout(maximium_wait_for_crash_reporter_) here
+  // because it causes shutdown hangs if the user tries to exit right after the
+  // crash_reporter is spawned. So call a delayed task to clean up after
+  // crash_reporter is finished.
+  base::Time process_creation_time = process.CreationTime();
+  base::ThreadPool::PostDelayedTask(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&ChromeJsErrorReportProcessor::WaitForCrashReporter, this,
+                     std::move(process), process_creation_time,
+                     std::move(cleanup), std::move(callback_runner)),
+      maximium_wait_for_crash_reporter_);
 }
 
 void ChromeJsErrorReportProcessor::SendReport(
@@ -180,9 +206,11 @@
   // get more metadata and to keep all the consent logic in one place. We need
   // to do file I/O, so over to a blockable thread for the send and then back to
   // the UI thread for the finished callback.
-  base::ThreadPool::PostTaskAndReply(
+  base::ThreadPool::PostTask(
       FROM_HERE, {base::MayBlock()},
-      base::BindOnce(&ChromeJsErrorReportProcessor::SendReportViaCrashReporter,
-                     this, std::move(params), std::move(stack_trace)),
-      callback_runner.Release());
+      base::BindOnce(
+          &ChromeJsErrorReportProcessor::SendReportViaCrashReporter, this,
+          std::move(params), std::move(stack_trace),
+          base::ScopedClosureRunner(base::BindPostTask(
+              content::GetUIThreadTaskRunner({}), callback_runner.Release()))));
 }
diff --git a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
index fe3b5ada..6fabf08 100644
--- a/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
+++ b/chrome/browser/error_reporting/mock_chrome_js_error_report_processor.cc
@@ -11,6 +11,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/strcat.h"
+#include "base/time/time.h"
 #include "components/crash/content/browser/error_reporting/javascript_error_report.h"
 #include "components/crash/content/browser/error_reporting/mock_crash_endpoint.h"
 #include "components/variations/variations_crash_keys.h"
@@ -24,7 +25,16 @@
     "6598898b-ac59b6dc%2C";  // The URL escaping turns the comma into %2C in the
                              // query string.
 
-MockChromeJsErrorReportProcessor::MockChromeJsErrorReportProcessor() = default;
+// Tricium gets confused by the #if's and thinks we should change this to
+// "= default".
+// NOLINTNEXTLINE
+MockChromeJsErrorReportProcessor::MockChromeJsErrorReportProcessor() {
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+  // Shorten timeout or tests will time out.
+  set_maximium_wait_for_crash_reporter_for_test(
+      base::TimeDelta::FromSeconds(5));
+#endif
+}
 
 MockChromeJsErrorReportProcessor::~MockChromeJsErrorReportProcessor() = default;
 
diff --git a/chrome/browser/extensions/api/commands/DIR_METADATA b/chrome/browser/extensions/api/commands/DIR_METADATA
index e16d0d54..637eb4dc 100644
--- a/chrome/browser/extensions/api/commands/DIR_METADATA
+++ b/chrome/browser/extensions/api/commands/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Platform>Extensions>API"
 }
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/extensions/api/gcm/DIR_METADATA b/chrome/browser/extensions/api/gcm/DIR_METADATA
index 8b9e15e..356995f 100644
--- a/chrome/browser/extensions/api/gcm/DIR_METADATA
+++ b/chrome/browser/extensions/api/gcm/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Services>CloudMessaging"
 }
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/extensions/api/instance_id/DIR_METADATA b/chrome/browser/extensions/api/instance_id/DIR_METADATA
index e16d0d54..637eb4dc 100644
--- a/chrome/browser/extensions/api/instance_id/DIR_METADATA
+++ b/chrome/browser/extensions/api/instance_id/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Platform>Extensions>API"
 }
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/extensions/api/notifications/DIR_METADATA b/chrome/browser/extensions/api/notifications/DIR_METADATA
deleted file mode 100644
index 81a57a13..0000000
--- a/chrome/browser/extensions/api/notifications/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/extensions/api/omnibox/omnibox_api.cc b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
index 3ccf5ea..bcf25bd 100644
--- a/chrome/browser/extensions/api/omnibox/omnibox_api.cc
+++ b/chrome/browser/extensions/api/omnibox/omnibox_api.cc
@@ -75,9 +75,7 @@
   std::unique_ptr<base::DictionaryValue> dict = suggestion.ToValue();
   // Add the content field so that the dictionary can be used to populate an
   // omnibox::SuggestResult.
-  dict->SetWithoutPathExpansion(
-      kSuggestionContent,
-      std::make_unique<base::Value>(base::Value::Type::STRING));
+  dict->SetKey(kSuggestionContent, base::Value(base::Value::Type::STRING));
   prefs->UpdateExtensionPref(extension_id, kOmniboxDefaultSuggestion,
                              std::move(dict));
 
diff --git a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
index f9320a7..146d627 100644
--- a/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
+++ b/chrome/browser/extensions/api/storage/settings_sync_unittest.cc
@@ -1404,8 +1404,7 @@
       ASSERT_TRUE(data.status().ok());
 
       base::DictionaryValue expected_data;
-      expected_data.SetWithoutPathExpansion(
-          "key.with.dot", std::make_unique<base::Value>("value"));
+      expected_data.SetKey("key.with.dot", base::Value("value"));
       EXPECT_EQ(expected_data, data.settings());
     }
 
diff --git a/chrome/browser/extensions/api/storage/sync_storage_backend.cc b/chrome/browser/extensions/api/storage/sync_storage_backend.cc
index 6de4467..ce2f024 100644
--- a/chrome/browser/extensions/api/storage/sync_storage_backend.cc
+++ b/chrome/browser/extensions/api/storage/sync_storage_backend.cc
@@ -194,7 +194,8 @@
     DCHECK(!settings->HasKey(data.key()))
         << "Duplicate settings for " << data.extension_id() << "/"
         << data.key();
-    settings->SetWithoutPathExpansion(data.key(), data.PassValue());
+    settings->SetKey(data.key(),
+                     base::Value::FromUniquePtrValue(data.PassValue()));
   }
 
   // Start syncing all existing storage areas.  Any storage areas created in
diff --git a/chrome/browser/extensions/component_extensions_allowlist/DIR_METADATA b/chrome/browser/extensions/component_extensions_allowlist/DIR_METADATA
deleted file mode 100644
index 81a57a13..0000000
--- a/chrome/browser/extensions/component_extensions_allowlist/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/extensions/extension_assets_manager_chromeos.cc b/chrome/browser/extensions/extension_assets_manager_chromeos.cc
index e6a7c70..c48d288 100644
--- a/chrome/browser/extensions/extension_assets_manager_chromeos.cc
+++ b/chrome/browser/extensions/extension_assets_manager_chromeos.cc
@@ -410,8 +410,8 @@
           base::BindOnce(std::move(info.callback), shared_version_dir));
   }
   version_info->Set(kSharedExtensionUsers, std::move(users));
-  extension_info_weak->SetWithoutPathExpansion(version,
-                                               std::move(version_info));
+  extension_info_weak->SetKey(
+      version, base::Value::FromUniquePtrValue(std::move(version_info)));
 }
 
 // static
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
index 6a072ab..05765fc 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -112,8 +112,8 @@
     }
     version_info->Set(ExtensionAssetsManagerChromeOS::kSharedExtensionUsers,
                       std::move(users));
-    extension_info_weak->SetWithoutPathExpansion(version,
-                                                 std::move(version_info));
+    extension_info_weak->SetKey(
+        version, base::Value::FromUniquePtrValue(std::move(version_info)));
   }
 
   scoped_refptr<const Extension> CreateExtension(const std::string& id,
diff --git a/chrome/browser/extensions/extension_management_test_util.cc b/chrome/browser/extensions/extension_management_test_util.cc
index 073d63c3..2c48400e 100644
--- a/chrome/browser/extensions/extension_management_test_util.cc
+++ b/chrome/browser/extensions/extension_management_test_util.cc
@@ -53,7 +53,7 @@
 void ExtensionManagementPrefUpdaterBase::ClearPerExtensionSettings(
     const ExtensionId& id) {
   DCHECK(crx_file::id_util::IdIsValid(id));
-  pref_->SetWithoutPathExpansion(id, std::make_unique<base::DictionaryValue>());
+  pref_->SetKey(id, base::DictionaryValue());
 }
 
 // Helper functions for 'installation_mode' manipulation -----------------------
diff --git a/chrome/browser/extensions/extension_migrator.cc b/chrome/browser/extensions/extension_migrator.cc
index cb39532..514ea91 100644
--- a/chrome/browser/extensions/extension_migrator.cc
+++ b/chrome/browser/extensions/extension_migrator.cc
@@ -33,7 +33,7 @@
     entry->SetKey(ExternalProviderImpl::kExternalUpdateUrl,
                   base::Value(extension_urls::GetWebstoreUpdateUrl().spec()));
 
-    prefs->SetWithoutPathExpansion(new_id_, std::move(entry));
+    prefs->SetKey(new_id_, base::Value::FromUniquePtrValue(std::move(entry)));
   }
 
   LoadFinished(std::move(prefs));
diff --git a/chrome/browser/extensions/updater/DIR_METADATA b/chrome/browser/extensions/updater/DIR_METADATA
deleted file mode 100644
index 81a57a13..0000000
--- a/chrome/browser/extensions/updater/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 2abc672..0b1f3c64 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -951,7 +951,7 @@
   {
     "name": "detect-target-embedding-lookalikes",
     "owners": [ "jdeblasio", "meacer" ],
-    "expiry_milestone": 89
+    "expiry_milestone": 93
   },
   {
     "name": "detected-source-language-option",
@@ -1268,7 +1268,7 @@
   {
     "name": "enable-aria-element-reflection",
     "owners": [ "aboxhall", "chrishall", "dmazzoni", "meredithl" ],
-    "expiry_milestone": 92
+    "expiry_milestone": 98
   },
   {
     "name": "enable-assistant-aec",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index eabf57d..629471d 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -4020,10 +4020,6 @@
     "Download the termina VM using the new DLC service instead of the old "
     "component updater.";
 
-const char kCrostiniEnableDlcName[] = "Crostini Enable DLC";
-const char kCrostiniEnableDlcDescription[] =
-    "Signal to Crostini that the DLC service is available for use.";
-
 const char kCrostiniResetLxdDbName[] = "Crostini Reset LXD DB on launch";
 const char kCrostiniResetLxdDbDescription[] =
     "Recreates the LXD database every time we launch it";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index abdf70e..9b8d736 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2325,9 +2325,6 @@
 extern const char kCrostiniUseDlcName[];
 extern const char kCrostiniUseDlcDescription[];
 
-extern const char kCrostiniEnableDlcName[];
-extern const char kCrostiniEnableDlcDescription[];
-
 extern const char kCrostiniResetLxdDbName[];
 extern const char kCrostiniResetLxdDbDescription[];
 
diff --git a/chrome/browser/gsa/DIR_METADATA b/chrome/browser/gsa/DIR_METADATA
index b0e6281..00ac528 100644
--- a/chrome/browser/gsa/DIR_METADATA
+++ b/chrome/browser/gsa/DIR_METADATA
@@ -1,6 +1,2 @@
 team_email : "chromium-reviews@chromium.org"
 os: ANDROID
-monorail {
-  project: "chromium"
-  component :"UI>Browser"
-}
\ No newline at end of file
diff --git a/chrome/browser/image_decoder/DIR_METADATA b/chrome/browser/image_decoder/DIR_METADATA
deleted file mode 100644
index d182185..0000000
--- a/chrome/browser/image_decoder/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/lacros/automation_manager_lacros.cc b/chrome/browser/lacros/automation_manager_lacros.cc
index 4a7eac7b..c5bbbfb 100644
--- a/chrome/browser/lacros/automation_manager_lacros.cc
+++ b/chrome/browser/lacros/automation_manager_lacros.cc
@@ -78,7 +78,10 @@
     const ui::AXActionData& data,
     bool result,
     content::BrowserContext* browser_context) {
-  // TODO(https://crbug.com/1185764): Implement me.
+  if (!automation_remote_)
+    return;
+
+  automation_remote_->DispatchActionResult(data, result);
 }
 void AutomationManagerLacros::DispatchGetTextLocationDataResult(
     const ui::AXActionData& data,
diff --git a/chrome/browser/language/android/BUILD.gn b/chrome/browser/language/android/BUILD.gn
index 8decc4e..3f719b3 100644
--- a/chrome/browser/language/android/BUILD.gn
+++ b/chrome/browser/language/android/BUILD.gn
@@ -21,6 +21,7 @@
 
 android_library("java") {
   sources = [
+    "java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java",
     "java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java",
     "java/src/org/chromium/chrome/browser/language/settings/AlwaysTranslateListFragment.java",
     "java/src/org/chromium/chrome/browser/language/settings/AppLanguagePreferenceDelegate.java",
@@ -50,6 +51,7 @@
     "//components/browser_ui/settings/android:java",
     "//components/browser_ui/widget/android:java",
     "//components/embedder_support/android:browser_context_java",
+    "//components/language/android:language_bridge_java",
     "//components/prefs/android:java",
     "//components/user_prefs/android:java",
     "//content/public/android:content_java",
@@ -70,11 +72,15 @@
   sources =
       [ "java/src/org/chromium/chrome/browser/translate/TranslateBridge.java" ]
 }
+
 android_resources("java_resources") {
   sources = [
     "java/res/layout/accept_languages_item.xml",
     "java/res/layout/accept_languages_list.xml",
     "java/res/layout/add_languages_main.xml",
+    "java/res/layout/language_ask_prompt_content.xml",
+    "java/res/layout/language_ask_prompt_row.xml",
+    "java/res/layout/language_ask_prompt_row_separator.xml",
     "java/res/layout/language_list_with_add_button.xml",
     "java/res/layout/languages_preference.xml",
     "java/res/layout/preference_category_no_title_or_padding.xml",
@@ -90,3 +96,47 @@
     "//ui/android:ui_java_resources",
   ]
 }
+
+android_library("javatests") {
+  testonly = true
+
+  sources = [
+    "java/src/org/chromium/chrome/browser/language/settings/LanguagesManagerTest.java",
+    "java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java",
+  ]
+  deps = [
+    ":base_module_java",
+    ":java",
+    ":java_resources",
+    "//base:base_java",
+    "//base:base_java_test_support",
+    "//chrome/android:chrome_java",
+    "//chrome/browser/flags:java",
+    "//chrome/browser/preferences:java",
+    "//chrome/browser/profiles/android:java",
+    "//chrome/browser/settings:java",
+    "//chrome/browser/settings:test_support_java",
+    "//chrome/browser/tab:java",
+    "//chrome/browser/ui/messages/android:java",
+    "//chrome/test/android:chrome_java_test_support",
+    "//components/browser_ui/settings/android:java",
+    "//components/browser_ui/widget/android:java",
+    "//components/embedder_support/android:browser_context_java",
+    "//components/prefs/android:java",
+    "//components/user_prefs/android:java",
+    "//content/public/test/android:content_java_test_support",
+    "//third_party/android_support_test_runner:rules_java",
+    "//third_party/android_support_test_runner:runner_java",
+    "//third_party/androidx:androidx_annotation_annotation_java",
+    "//third_party/androidx:androidx_appcompat_appcompat_java",
+    "//third_party/androidx:androidx_core_core_java",
+    "//third_party/androidx:androidx_fragment_fragment_java",
+    "//third_party/androidx:androidx_preference_preference_java",
+    "//third_party/androidx:androidx_recyclerview_recyclerview_java",
+    "//third_party/androidx:androidx_test_runner_java",
+    "//third_party/junit",
+    "//third_party/mockito:mockito_java",
+    "//ui/android:ui_full_java",
+    "//ui/android:ui_no_recycler_view_java",
+  ]
+}
diff --git a/chrome/android/java/res/layout/language_ask_prompt_content.xml b/chrome/browser/language/android/java/res/layout/language_ask_prompt_content.xml
similarity index 100%
rename from chrome/android/java/res/layout/language_ask_prompt_content.xml
rename to chrome/browser/language/android/java/res/layout/language_ask_prompt_content.xml
diff --git a/chrome/android/java/res/layout/language_ask_prompt_row.xml b/chrome/browser/language/android/java/res/layout/language_ask_prompt_row.xml
similarity index 100%
rename from chrome/android/java/res/layout/language_ask_prompt_row.xml
rename to chrome/browser/language/android/java/res/layout/language_ask_prompt_row.xml
diff --git a/chrome/android/java/res/layout/language_ask_prompt_row_separator.xml b/chrome/browser/language/android/java/res/layout/language_ask_prompt_row_separator.xml
similarity index 100%
rename from chrome/android/java/res/layout/language_ask_prompt_row_separator.xml
rename to chrome/browser/language/android/java/res/layout/language_ask_prompt_row_separator.xml
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
similarity index 99%
rename from chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
rename to chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
index da1dd12..f631572 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
@@ -22,7 +22,6 @@
 import org.chromium.base.LocaleUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.supplier.ObservableSupplier;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.language.settings.LanguageItem;
 import org.chromium.chrome.browser.translate.TranslateBridge;
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java
index 6b17cbb..1c52196b 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AddLanguageFragment.java
@@ -39,11 +39,7 @@
     // Intent key to pass selected language code from AddLanguageFragment.
     static final String INTENT_SELECTED_LANGUAGE = "AddLanguageFragment.SelectedLanguages";
     // Intent key to receive type of languages to populate fragment with.
-    static final String INTENT_LANGUAGE_OPTIONS = "AddLanguageFragment.LanguageOptions";
-    // Intent keys to select language options to use.
-    static final int LANGUAGE_OPTIONS_ACCEPT_LANGUAGES = 0; // Default
-    static final int LANGUAGE_OPTIONS_UI_LANGUAGES = 1;
-    static final int LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES = 2;
+    static final String INTENT_POTENTIAL_LANGUAGES = "AddLanguageFragment.PotentialLanguages";
 
     /**
      * A host to launch AddLanguageFragment and receive the result.
@@ -73,14 +69,14 @@
          */
         private void search(String query) {
             if (TextUtils.isEmpty(query)) {
-                setDisplayedLanguages(mFullLanguageList);
+                setDisplayedLanguages(mFilteredLanguages);
                 return;
             }
 
             Locale locale = Locale.getDefault();
             query = query.trim().toLowerCase(locale);
             List<LanguageItem> results = new ArrayList<>();
-            for (LanguageItem item : mFullLanguageList) {
+            for (LanguageItem item : mFilteredLanguages) {
                 // TODO(crbug/783049): Consider searching in item's native display name and
                 // language code too.
                 if (item.getDisplayName().toLowerCase(locale).contains(query)) {
@@ -99,7 +95,7 @@
 
     private RecyclerView mRecyclerView;
     private LanguageSearchListAdapter mAdapter;
-    private List<LanguageItem> mFullLanguageList;
+    private List<LanguageItem> mFilteredLanguages;
     private LanguageListBaseAdapter.ItemClickListener mItemClickListener;
 
     @Override
@@ -127,17 +123,10 @@
         mRecyclerView.addItemDecoration(
                 new DividerItemDecoration(activity, layoutManager.getOrientation()));
 
+        @LanguagesManager.LanguageListType
         int languageOption = getActivity().getIntent().getIntExtra(
-                INTENT_LANGUAGE_OPTIONS, LANGUAGE_OPTIONS_ACCEPT_LANGUAGES);
-        if (languageOption == LANGUAGE_OPTIONS_UI_LANGUAGES) {
-            mFullLanguageList = LanguagesManager.getInstance().getAvailableUiLanguageItems();
-            mFullLanguageList.add(0, LanguageItem.makeSystemDefaultLanguageItem());
-        } else if (languageOption == LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES) {
-            mFullLanguageList = LanguagesManager.getInstance().getTranslateLanguageItems();
-        } else {
-            mFullLanguageList =
-                    LanguagesManager.getInstance().getLanguageItemsExcludingUserAccept();
-        }
+                INTENT_POTENTIAL_LANGUAGES, LanguagesManager.LanguageListType.ACCEPT_LANGUAGES);
+        mFilteredLanguages = LanguagesManager.getInstance().getPotentialLanguages(languageOption);
         mItemClickListener = item -> {
             Intent intent = new Intent();
             intent.putExtra(INTENT_SELECTED_LANGUAGE, item.getCode());
@@ -147,7 +136,7 @@
         mAdapter = new LanguageSearchListAdapter(activity);
 
         mRecyclerView.setAdapter(mAdapter);
-        mAdapter.setDisplayedLanguages(mFullLanguageList);
+        mAdapter.setDisplayedLanguages(mFilteredLanguages);
         mRecyclerView.getViewTreeObserver().addOnScrollChangedListener(
                 SettingsUtils.getShowShadowOnScrollListener(
                         mRecyclerView, view.findViewById(R.id.shadow)));
@@ -164,7 +153,7 @@
 
         mSearchView.setOnCloseListener(() -> {
             mSearch = "";
-            mAdapter.setDisplayedLanguages(mFullLanguageList);
+            mAdapter.setDisplayedLanguages(mFilteredLanguages);
             return false;
         });
 
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AlwaysTranslateListFragment.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AlwaysTranslateListFragment.java
index accaf8f..b6ea370 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AlwaysTranslateListFragment.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/AlwaysTranslateListFragment.java
@@ -27,6 +27,11 @@
     }
 
     @Override
+    protected @LanguagesManager.LanguageListType int getPotentialLanguageType() {
+        return LanguagesManager.LanguageListType.ALWAYS_LANGUAGES;
+    }
+
+    @Override
     protected void recordFragmentImpression() {
         LanguagesManager.recordImpression(
                 LanguagesManager.LanguageSettingsPageType.VIEW_ALWAYS_TRANSLATE_LANGUAGES);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java
index 0f3300a..0efbbfc 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItem.java
@@ -15,6 +15,7 @@
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * Simple object representing the language item.
@@ -38,7 +39,7 @@
     private boolean mSupportAppUI;
 
     /**
-     * Creates a new {@link LanguageItem}.
+     * Creates a new LanguageItem getting UI availability from ResourceBundle.
      * @param code The BCP-47 language tag for this language item.
      * @param displayName The display name of the language in the current app locale.
      * @param nativeDisplayName The display name of the language in the language's locale.
@@ -50,11 +51,7 @@
         mDisplayName = displayName;
         mNativeDisplayName = nativeDisplayName;
         mSupportTranslate = supportTranslate;
-        if (TextUtils.equals(code, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE)) {
-            mSupportAppUI = true; // system language is a supported UI language
-        } else {
-            mSupportAppUI = isAvailableUiLanguage(mCode);
-        }
+        mSupportAppUI = isAvailableUiLanguage(code);
     }
 
     /**
@@ -97,7 +94,7 @@
             return false;
         }
 
-        // Currently the only two country variants that are translateable are "zh-CN" and "zh-TW".
+        // Currently the only two country variants that are translateable are zh-CN and zh-TW.
         if (TextUtils.equals(mCode, "zh-CN") || TextUtils.equals(mCode, "zh-TW")) {
             return true;
         }
@@ -117,6 +114,32 @@
     }
 
     /**
+     * @return True if this language item represents the system default.
+     */
+    public boolean isSystemDefault() {
+        return TextUtils.equals(mCode, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE);
+    }
+
+    /**
+     * Return the hashCode of the language code for this LanguageItem. The language code can be
+     * used for the hash since two LanguageItems with equal langauge codes are equal.
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(mCode);
+    }
+
+    /**
+     * Two LanguageItems are equal if their language codes are equal.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof LanguageItem)) return false;
+        LanguageItem other = (LanguageItem) obj;
+        return TextUtils.equals(mCode, other.mCode);
+    }
+
+    /**
      * Create a LanguageItem representing the system default language.
      * @return LanguageItem
      */
@@ -126,8 +149,8 @@
         String nativeName =
                 GlobalAppLocaleController.getInstance().getOriginalSystemLocale().getDisplayName(
                         Locale.getDefault());
-        return new LanguageItem(
-                AppLocaleUtils.SYSTEM_LANGUAGE_VALUE, displayName, nativeName, true);
+        return new LanguageItem(AppLocaleUtils.SYSTEM_LANGUAGE_VALUE, displayName, nativeName,
+                true /*supportTranslate*/);
     }
 
     /**
@@ -135,6 +158,7 @@
      * @param language BCP-47 language tag representing a locale (e.g. "en-US")
      */
     public static boolean isAvailableUiLanguage(String language) {
+        if (Objects.equals(language, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE)) return true;
         return Arrays.binarySearch(ResourceBundle.getAvailableLocales(), language) >= 0;
     }
 }
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListFragment.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListFragment.java
index f303e1d..2407da5 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListFragment.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageItemListFragment.java
@@ -136,8 +136,8 @@
             recordAddLanguageImpression();
             Intent intent = mSettingsLauncher.createSettingsActivityIntent(
                     getActivity(), AddLanguageFragment.class.getName());
-            intent.putExtra(AddLanguageFragment.INTENT_LANGUAGE_OPTIONS,
-                    AddLanguageFragment.LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES);
+            intent.putExtra(
+                    AddLanguageFragment.INTENT_POTENTIAL_LANGUAGES, getPotentialLanguageType());
             startActivityForResult(intent, REQUEST_CODE_SELECT_LANGUAGE);
         });
 
@@ -161,7 +161,7 @@
     }
 
     /**
-     * Return the ListDelegate that will be used to populate the LangaugeItemList for a subclass.
+     * Return the ListDelegate that will be used to populate the LanguageItemList for a subclass.
      */
     protected abstract LanguageItemListFragment.ListDelegate makeFragmentListDelegate();
 
@@ -171,25 +171,30 @@
     protected abstract String getLanguageListTitle(Context context);
 
     /**
-     * Records the {@link LangaugesManager.LanguageSettingsPageType} impression for viewing this
+     * Return the type of potential languages to populate the add language fragment with.
+     */
+    protected abstract @LanguagesManager.LanguageListType int getPotentialLanguageType();
+
+    /**
+     * Records the {@link LanguagesManager.LanguageSettingsPageType} impression for viewing this
      * LanguageItemListFragment.
      */
     protected abstract void recordFragmentImpression();
 
     /**
-     * Records the {@link LangaugesManager.LanguageSettingsPageType} impression for viewing the
+     * Records the {@link LanguagesManager.LanguageSettingsPageType} impression for viewing the
      * Add Language page from this LanguageItemListFragment.
      */
     protected abstract void recordAddLanguageImpression();
 
     /**
-     * Records the {@link LangaugesManager.LanguageSettingsActionType} for adding to this
+     * Records the {@link LanguagesManager.LanguageSettingsActionType} for adding to this
      * LanguageItemListFragment.
      */
     protected abstract void recordAddAction();
 
     /**
-     * Records the {@link LangaugesManager.LanguageSettingsActionType} for removing from this
+     * Records the {@link LanguagesManager.LanguageSettingsActionType} for removing from this
      * LanguageItemListFragment.
      */
     protected abstract void recordRemoveAction();
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
index 9d04a58..ab4b0f0 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguageSettings.java
@@ -147,7 +147,7 @@
         appLanguagePreference.setLanguageItem(AppLocaleUtils.getAppLanguagePref());
         appLanguagePreference.useLanguageItemForTitle(true);
         setSelectLanguageLauncher(appLanguagePreference,
-                AddLanguageFragment.LANGUAGE_OPTIONS_UI_LANGUAGES, REQUEST_CODE_CHANGE_APP_LANGUAGE,
+                LanguagesManager.LanguageListType.UI_LANGUAGES, REQUEST_CODE_CHANGE_APP_LANGUAGE,
                 LanguagesManager.LanguageSettingsPageType.CHANGE_CHROME_LANGUAGE);
 
         mAppLanguageDelegate.setup(this, appLanguagePreference);
@@ -176,7 +176,7 @@
                 (LanguageItemPickerPreference) findPreference(TARGET_LANGUAGE_KEY);
         targetLanguagePreference.setLanguageItem(TranslateBridge.getTargetLanguageForChromium());
         setSelectLanguageLauncher(targetLanguagePreference,
-                AddLanguageFragment.LANGUAGE_OPTIONS_TRANSLATE_LANGUAGES,
+                LanguagesManager.LanguageListType.TARGET_LANGUAGES,
                 REQUEST_CODE_CHANGE_TARGET_LANGUAGE,
                 LanguagesManager.LanguageSettingsPageType.CHANGE_TARGET_LANGUAGE);
         mPrefChangeRegistrar.addObserver(Pref.PREF_TRANSLATE_RECENT_TARGET, () -> {
@@ -278,7 +278,7 @@
     public void launchAddLanguage() {
         LanguagesManager.recordImpression(
                 LanguagesManager.LanguageSettingsPageType.CONTENT_LANGUAGE_ADD_LANGUAGE);
-        launchSelectLanguage(AddLanguageFragment.LANGUAGE_OPTIONS_ACCEPT_LANGUAGES,
+        launchSelectLanguage(LanguagesManager.LanguageListType.ACCEPT_LANGUAGES,
                 REQUEST_CODE_ADD_ACCEPT_LANGUAGE);
     }
 
@@ -305,13 +305,14 @@
      * @param int requestCode The code to return from the select language fragment with.
      * @param int pageType The LanguageSettingsPageType to record impression for.
      */
-    private void setSelectLanguageLauncher(Preference preference, int launchCode, int requestCode,
+    private void setSelectLanguageLauncher(Preference preference,
+            @LanguagesManager.LanguageListType int languageListType, int requestCode,
             @LanguagesManager.LanguageSettingsPageType int pageType) {
         preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
             @Override
             public boolean onPreferenceClick(Preference preference) {
                 LanguagesManager.recordImpression(pageType);
-                launchSelectLanguage(launchCode, requestCode);
+                launchSelectLanguage(languageListType, requestCode);
                 return true;
             }
         });
@@ -322,10 +323,11 @@
      * @param int launchCode The language options code to filter selectable languages.
      * @param int requestCode The code to return from the select language fragment with.
      */
-    private void launchSelectLanguage(int launchCode, int requestCode) {
+    private void launchSelectLanguage(
+            @LanguagesManager.LanguageListType int languageListType, int requestCode) {
         Intent intent = mSettingsLauncher.createSettingsActivityIntent(
                 getActivity(), AddLanguageFragment.class.getName());
-        intent.putExtra(AddLanguageFragment.INTENT_LANGUAGE_OPTIONS, launchCode);
+        intent.putExtra(AddLanguageFragment.INTENT_POTENTIAL_LANGUAGES, languageListType);
         startActivityForResult(intent, requestCode);
     }
 
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java
index 9060175..ee25322 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManager.java
@@ -4,17 +4,24 @@
 
 package org.chromium.chrome.browser.language.settings;
 
+import android.text.TextUtils;
+
 import androidx.annotation.IntDef;
+import androidx.core.util.Predicate;
 
 import org.chromium.base.LocaleUtils;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.language.AppLocaleUtils;
 import org.chromium.chrome.browser.translate.TranslateBridge;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeSet;
@@ -103,6 +110,19 @@
         int NUM_ENTRIES = 12;
     }
 
+    // Int keys to determine the list of potential languages for different language preferences.
+    @IntDef({LanguageListType.ACCEPT_LANGUAGES, LanguageListType.UI_LANGUAGES,
+            LanguageListType.TARGET_LANGUAGES, LanguageListType.NEVER_LANGUAGES,
+            LanguageListType.ALWAYS_LANGUAGES})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface LanguageListType {
+        int ACCEPT_LANGUAGES = 0; // Default
+        int UI_LANGUAGES = 1;
+        int TARGET_LANGUAGES = 2;
+        int NEVER_LANGUAGES = 3;
+        int ALWAYS_LANGUAGES = 4;
+    }
+
     private static LanguagesManager sManager;
 
     private final Map<String, LanguageItem> mLanguagesMap;
@@ -145,42 +165,100 @@
     }
 
     /**
+     * Get the list of potential languages to show in the {@link AddLanguageFragment} based on which
+     * list or preference a language will be added to. By default the potential languages for the
+     * Accept-Language list is returned.
+     * @param LanguageListType key to select which languages to get.
+     * @return A list of LanguageItems to choose from for the given preference.
+     */
+    public List<LanguageItem> getPotentialLanguages(@LanguageListType int potentialLanguages) {
+        switch (potentialLanguages) {
+            case LanguageListType.ALWAYS_LANGUAGES:
+                return getPotentialTranslateLanguages(
+                        TranslateBridge.getAlwaysTranslateLanguages());
+            case LanguageListType.NEVER_LANGUAGES:
+                return getPotentialTranslateLanguages(TranslateBridge.getNeverTranslateLanguages());
+            case LanguageListType.TARGET_LANGUAGES:
+                return getPotentialTranslateLanguages(
+                        Arrays.asList(TranslateBridge.getTargetLanguageForChromium()));
+            case LanguageListType.UI_LANGUAGES:
+                return getPotentialUiLanguages();
+            case LanguageListType.ACCEPT_LANGUAGES:
+                return getPotentialAcceptLanguages();
+            default:
+                assert false : "No valid LanguageListType";
+                return null;
+        }
+    }
+
+    /**
+     * Get a list of LanguageItems that can be used as a Translate language but excluding
+     * |codesToSkip|. The current Accept-Languages are added to the front of the list.
+     * @param codesToSkip Collection of String language codes to exclude from the list.
+     * @return List of LanguageItems.
+     */
+    private List<LanguageItem> getPotentialTranslateLanguages(Collection<String> codesToSkip) {
+        HashSet<String> codesToSkipSet = new HashSet<String>(codesToSkip);
+        LinkedHashSet<LanguageItem> results = new LinkedHashSet<>();
+        // Filter for translatable languages not in |codesToSkipSet|.
+        Predicate<LanguageItem> filter = (item) -> {
+            return item.isSupportedBaseLanguage() && !codesToSkipSet.contains(item.getCode());
+        };
+        addItemsToResult(results, getUserAcceptLanguageItems(), filter);
+        addItemsToResult(results, mLanguagesMap.values(), filter);
+        return new ArrayList<>(results);
+    }
+
+    /**
+     * Get a list of potential LanguageItems Chrome UI languages excluding the current UI language.
+     * The current Accept-Languages are added to the front of the the list.
+     * @return List of LanguageItems.
+     */
+    private List<LanguageItem> getPotentialUiLanguages() {
+        LinkedHashSet<LanguageItem> results = new LinkedHashSet<>();
+        LanguageItem currentUiLanguage = getLanguageItem(AppLocaleUtils.getAppLanguagePref());
+
+        // Add the system default language if an override language is set.
+        if (!currentUiLanguage.isSystemDefault()) {
+            results.add(LanguageItem.makeSystemDefaultLanguageItem());
+        }
+
+        // Filter for UI languages that are not the current UI language.
+        Predicate<LanguageItem> filter = (item) -> {
+            return item.isUISupported() && !item.equals(currentUiLanguage);
+        };
+        addItemsToResult(results, getUserAcceptLanguageItems(), filter);
+        addItemsToResult(results, mLanguagesMap.values(), filter);
+        return new ArrayList<>(results);
+    }
+
+    /**
+     * Get a list of potential Accept-Languages excluding the current Accept-Languages.
      * @return A list of LanguageItems, excluding the current user's accept languages.
      */
-    public List<LanguageItem> getLanguageItemsExcludingUserAccept() {
+    private List<LanguageItem> getPotentialAcceptLanguages() {
         // Always read the latest user accept language code list from native.
-        List<String> codes = TranslateBridge.getUserLanguageCodes();
-
-        List<LanguageItem> results = new ArrayList<>();
-        // Keep the same order as mLanguagesMap.
-        for (LanguageItem item : mLanguagesMap.values()) {
-            if (!codes.contains(item.getCode())) results.add(item);
-        }
-        return results;
+        HashSet<String> codesToSkip = new HashSet(TranslateBridge.getUserLanguageCodes());
+        LinkedHashSet<LanguageItem> results = new LinkedHashSet<>();
+        addItemsToResult(
+                results, mLanguagesMap.values(), (item) -> !codesToSkip.contains(item.getCode()));
+        return new ArrayList<>(results);
     }
 
     /**
-     * Get a list of LanguageItems that can be Chrome UI languages.
-     * @return List of LanguageItems.
+     * Add LanguageItems in |items| to |results| keeping their order and excluding items that match
+     * |filter|.
+     * @param results LinkedHashSet of LanguageItems to add items to.
+     * @param items Collection of LanguageItems to potentially add to results.
+     * @param filter Predicate to return true for items that should be added to results.
      */
-    public List<LanguageItem> getAvailableUiLanguageItems() {
-        List<LanguageItem> results = new ArrayList<>();
-        for (LanguageItem item : mLanguagesMap.values()) {
-            if (item.isUISupported()) results.add(item);
+    private void addItemsToResult(LinkedHashSet<LanguageItem> results,
+            Collection<LanguageItem> items, Predicate<LanguageItem> filter) {
+        for (LanguageItem item : items) {
+            if (filter.test(item)) {
+                results.add(item);
+            }
         }
-        return results;
-    }
-
-    /**
-     * Get a list of all LanguageItems that are supported by translate.
-     * @return List of LanguageItems.
-     */
-    public List<LanguageItem> getTranslateLanguageItems() {
-        List<LanguageItem> results = new ArrayList<>();
-        for (LanguageItem item : mLanguagesMap.values()) {
-            if (item.isSupportedBaseLanguage()) results.add(item);
-        }
-        return results;
     }
 
     /**
@@ -214,11 +292,14 @@
     }
 
     /**
-     * Get a LanguageItem given the iso639 locale code (e.g. en-US).  If no direct match is found
-     * only the language is checked. If there is still no match null is returned.
+     * Get a LanguageItem given the iso639 locale code (e.g. en-US). If no match is found the base
+     * language is checked (e.g. "en" for "en-AU"). If there is still no match null is returned.
      * @return LanguageItem or null if none found
      */
     public LanguageItem getLanguageItem(String localeCode) {
+        if (TextUtils.equals(localeCode, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE)) {
+            return LanguageItem.makeSystemDefaultLanguageItem();
+        }
         LanguageItem result = mLanguagesMap.get(localeCode);
         if (result != null) return result;
 
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManagerTest.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManagerTest.java
new file mode 100644
index 0000000..03f69bbc
--- /dev/null
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/LanguagesManagerTest.java
@@ -0,0 +1,246 @@
+// 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.language.settings;
+
+import android.text.TextUtils;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.flags.ChromeSwitches;
+import org.chromium.chrome.browser.language.AppLocaleUtils;
+import org.chromium.chrome.browser.translate.FakeTranslateBridgeJni;
+import org.chromium.chrome.browser.translate.TranslateBridge;
+import org.chromium.chrome.browser.translate.TranslateBridgeJni;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for {@link LanguagesManager} which gets language lists from native.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+public class LanguagesManagerTest {
+    @Rule
+    public JniMocker mJniMocker = new JniMocker();
+
+    private FakeTranslateBridgeJni mFakeTranslateBridge;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        // Setup fake translate and langauge preferences.
+        List<LanguageItem> chromeLanguages = FakeTranslateBridgeJni.getSimpleLanguageItemList();
+        List<String> acceptLanguages = Arrays.asList("sw", "en", "en-US");
+        List<String> neverLanguages = Arrays.asList("en");
+        List<String> alwaysLanguages = new ArrayList();
+        String targetLanguage = "en";
+        mFakeTranslateBridge = new FakeTranslateBridgeJni(
+                chromeLanguages, acceptLanguages, neverLanguages, alwaysLanguages, targetLanguage);
+        mJniMocker.mock(TranslateBridgeJni.TEST_HOOKS, mFakeTranslateBridge);
+    }
+
+    /**
+     * Tests for getting the potential accept languages.
+     */
+    @Test
+    @SmallTest
+    public void testGetPotentialAcceptLanguages() {
+        List<LanguageItem> items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.ACCEPT_LANGUAGES);
+
+        // The default accept languages list is "sw,en,en-US". Those languages should not be
+        // in the potential languages for Accept Languages.
+        Assert.assertFalse(containsLanguage(items, "sw"));
+        Assert.assertFalse(containsLanguage(items, "en"));
+        Assert.assertFalse(containsLanguage(items, "en-US"));
+        // But other languages should be.
+        Assert.assertEquals(mFakeTranslateBridge.getChromeLanguagesCount() - 3, items.size());
+        Assert.assertTrue(containsLanguage(items, "en-GB"));
+
+        // The first language should be Afrikaans.
+        Assert.assertEquals(items.get(0).getCode(), "af");
+
+        // Add "af" to front of Accept-Languages.
+        items = LanguagesManager.getInstance().getUserAcceptLanguageItems();
+        items.add(0, LanguagesManager.getInstance().getLanguageItem("af"));
+        setOrder(items);
+
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.ACCEPT_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "en"));
+        Assert.assertFalse(containsLanguage(items, "en-US"));
+        // Now "af" should not be in the list.
+        Assert.assertFalse(containsLanguage(items, "af"));
+        Assert.assertTrue(containsLanguage(items, "en-GB"));
+    }
+
+    /**
+     * Tests for getting the potential UI languages.
+     */
+    @Test
+    @SmallTest
+    public void testGetPotentialUiLanguages() {
+        // Set UI Language to Swahili.
+        AppLocaleUtils.setAppLanguagePref("sw");
+
+        List<LanguageItem> items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.UI_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "en"));
+        Assert.assertTrue(containsLanguage(items, "en-US"));
+        Assert.assertTrue(containsLanguage(items, "en-GB"));
+
+        // Languages that can not be UI languages are not present.
+        Assert.assertFalse(containsLanguage(items, "xh"));
+        Assert.assertFalse(containsLanguage(items, "wa"));
+
+        // Check that the current UI language (Swahili) is not on the list.
+        Assert.assertFalse(containsLanguage(items, "sw"));
+
+        // Check that the first language is the system default language.
+        Assert.assertEquals(items.get(0).getCode(), AppLocaleUtils.SYSTEM_LANGUAGE_VALUE);
+        // Check that the second language is "en-US" from the Accept-Languages.
+        Assert.assertEquals(items.get(1).getCode(), "en-US");
+
+        // Set UI Language to system default.
+        AppLocaleUtils.setAppLanguagePref(AppLocaleUtils.SYSTEM_LANGUAGE_VALUE);
+
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.UI_LANGUAGES);
+
+        // Check that system default is not on the list and that German is.
+        Assert.assertFalse(containsLanguage(items, AppLocaleUtils.SYSTEM_LANGUAGE_VALUE));
+        // Check that the fist languages are from the Accept-Languages.
+        Assert.assertEquals(items.get(0).getCode(), "sw");
+        Assert.assertEquals(items.get(1).getCode(), "en-US");
+    }
+
+    /**
+     * Tests for getting the potential target languages.
+     */
+    @Test
+    @SmallTest
+    public void testGetPotentialTargetLanguages() {
+        List<LanguageItem> items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.TARGET_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "en-US"));
+        Assert.assertFalse(containsLanguage(items, "en-GB"));
+        Assert.assertTrue(containsLanguage(items, "fil"));
+
+        // Check that the default target language "en" is not in the list.
+        Assert.assertFalse(containsLanguage(items, "en"));
+
+        // Check that the first language is "sw" from the Accept-Languages.
+        Assert.assertEquals(items.get(0).getCode(), "sw");
+
+        // Set the target language to "fil" (Filipino) which is "tl" as a Translate language.
+        TranslateBridge.setDefaultTargetLanguage("fil");
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.TARGET_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "fil"));
+        Assert.assertTrue(containsLanguage(items, "en"));
+
+        // Set the target language to "sw" (Swahili).
+        TranslateBridge.setDefaultTargetLanguage("sw");
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.TARGET_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "sw"));
+        Assert.assertTrue(containsLanguage(items, "fil"));
+    }
+
+    /**
+     * Tests for getting the potential always translate languages.
+     */
+    @Test
+    @SmallTest
+    public void testGetPotentialAlwaysLanguages() {
+        List<LanguageItem> items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.ALWAYS_LANGUAGES);
+        int itemsCount = items.size();
+
+        Assert.assertTrue(containsLanguage(items, "en"));
+        Assert.assertFalse(containsLanguage(items, "en-US"));
+        Assert.assertFalse(containsLanguage(items, "en-GB"));
+        Assert.assertTrue(containsLanguage(items, "fil"));
+
+        // Check that the first language is "sw" from the Accept-Languages.
+        Assert.assertEquals(items.get(0).getCode(), "sw");
+
+        // Add English and Filipino to always translate languages.
+        TranslateBridge.setLanguageAlwaysTranslateState("en", true);
+        TranslateBridge.setLanguageAlwaysTranslateState("fil", true);
+
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.ALWAYS_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "fil"));
+        Assert.assertFalse(containsLanguage(items, "en"));
+        Assert.assertEquals(itemsCount - 2, items.size());
+    }
+
+    /**
+     * Test for getting the potential never translate languages.
+     */
+    @Test
+    @SmallTest
+    public void testGetPotentialNeverLanguages() {
+        List<LanguageItem> items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.NEVER_LANGUAGES);
+        int itemsCount = items.size();
+
+        // English is the default never translate language.
+        Assert.assertFalse(containsLanguage(items, "en"));
+        Assert.assertFalse(containsLanguage(items, "en-US"));
+        Assert.assertFalse(containsLanguage(items, "en-GB"));
+        Assert.assertTrue(containsLanguage(items, "af"));
+        Assert.assertTrue(containsLanguage(items, "fil"));
+
+        // Check that the second language is "sw" from the Accept-Languages.
+        Assert.assertEquals(items.get(0).getCode(), "sw");
+
+        TranslateBridge.setLanguageBlockedState("fil", true);
+        TranslateBridge.setLanguageBlockedState("sw", true);
+
+        items = LanguagesManager.getInstance().getPotentialLanguages(
+                LanguagesManager.LanguageListType.NEVER_LANGUAGES);
+        Assert.assertFalse(containsLanguage(items, "fil"));
+        Assert.assertFalse(containsLanguage(items, "sw"));
+        Assert.assertEquals(itemsCount - 2, items.size());
+    }
+
+    /**
+     * @param languageList List of LanguageItems.
+     * @param language String language code to check for.
+     * @return boolean True if |languageList has a {@link LanguageItem} matching |language|.
+     */
+    private boolean containsLanguage(List<LanguageItem> languageList, String language) {
+        for (LanguageItem item : languageList) {
+            if (TextUtils.equals(item.getCode(), language)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * param languages List of LanguageItems in the order to set Accept-Languages to.
+     */
+    private void setOrder(List<LanguageItem> languages) {
+        String[] codes = new String[languages.size()];
+        int i = 0;
+        for (LanguageItem item : languages) {
+            codes[i++] = item.getCode();
+        }
+        TranslateBridge.setLanguageOrder(codes);
+    }
+}
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/NeverTranslateListFragment.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/NeverTranslateListFragment.java
index 25de203..53c31325 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/NeverTranslateListFragment.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/language/settings/NeverTranslateListFragment.java
@@ -28,6 +28,11 @@
     }
 
     @Override
+    protected @LanguagesManager.LanguageListType int getPotentialLanguageType() {
+        return LanguagesManager.LanguageListType.NEVER_LANGUAGES;
+    }
+
+    @Override
     protected void recordFragmentImpression() {
         LanguagesManager.recordImpression(
                 LanguagesManager.LanguageSettingsPageType.VIEW_NEVER_TRANSLATE_LANGUAGES);
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java
new file mode 100644
index 0000000..76092a2
--- /dev/null
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/FakeTranslateBridgeJni.java
@@ -0,0 +1,233 @@
+// 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.translate;
+
+import org.chromium.chrome.browser.language.settings.LanguageItem;
+import org.chromium.content_public.browser.WebContents;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.TreeMap;
+
+/**
+ * Fake implementation of the TranslateBridge native methods that provides support for the language
+ * preferences methods. An implementation for methods actually translating WebContents is not.
+ *
+ * Use FakeTranslateBridgeJni.getSimpleLanguageItemList() to get a fake list of LanguageItems with
+ * only 9 languages potentail Accept-Languages that represent a mix of acceptable UI and translate
+ * languages.
+ */
+public class FakeTranslateBridgeJni implements TranslateBridge.Natives {
+    private String mTargetLanguage;
+    private ArrayList<String> mUserAcceptLanguages;
+    private LinkedHashSet<String> mDefaultUserAcceptLanguages;
+    private HashSet<String> mNeverLanguages;
+    private HashSet<String> mAlwaysLanguages;
+    private TreeMap<String, LanguageItem> mChromeLanguages;
+
+    public FakeTranslateBridgeJni(Collection<LanguageItem> chromeLanguages,
+            Collection<String> userAcceptLanguages, Collection<String> neverLanguages,
+            Collection<String> alwaysLanguages, String targetLanguage) {
+        mChromeLanguages = new TreeMap<String, LanguageItem>();
+        for (LanguageItem item : chromeLanguages) {
+            mChromeLanguages.put(item.getDisplayName(), item);
+        }
+        mUserAcceptLanguages = new ArrayList(userAcceptLanguages);
+        mDefaultUserAcceptLanguages = new LinkedHashSet(userAcceptLanguages);
+        mNeverLanguages = new HashSet(neverLanguages);
+        mAlwaysLanguages = new HashSet(alwaysLanguages);
+        mTargetLanguage = targetLanguage;
+    }
+
+    @Override
+    public void getChromeAcceptLanguages(List<LanguageItem> list) {
+        list.addAll(mChromeLanguages.values());
+    }
+
+    @Override
+    public void getUserAcceptLanguages(List<String> list) {
+        list.addAll(mUserAcceptLanguages);
+    }
+
+    /**
+     * Reset the user Accept-Languages to the default list and prepend |defaultLocale| if needed.
+     */
+    @Override
+    public void resetAcceptLanguages(String defaultLocale) {
+        mUserAcceptLanguages = new ArrayList<>();
+        if (!mDefaultUserAcceptLanguages.contains(defaultLocale)) {
+            mUserAcceptLanguages.add(defaultLocale);
+        }
+        mUserAcceptLanguages.addAll(mDefaultUserAcceptLanguages);
+    }
+
+    /**
+     * Set the Accept-Languages to the new list of strings.
+     */
+    @Override
+    public void setLanguageOrder(String[] codes) {
+        mUserAcceptLanguages = new ArrayList<>(Arrays.asList(codes));
+    }
+
+    @Override
+    public void updateUserAcceptLanguages(String language, boolean add) {
+        if (!add) {
+            mUserAcceptLanguages.remove(language);
+        } else if (!mUserAcceptLanguages.contains(language)) {
+            mUserAcceptLanguages.add(language);
+        }
+    }
+
+    @Override
+    public String getTargetLanguage() {
+        return mTargetLanguage;
+    }
+
+    @Override
+    public void setDefaultTargetLanguage(String targetLanguage) {
+        mTargetLanguage = targetLanguage;
+    }
+
+    @Override
+    public void getAlwaysTranslateLanguages(List<String> list) {
+        list.addAll(mAlwaysLanguages);
+    }
+
+    @Override
+    public void setLanguageAlwaysTranslateState(String language, boolean alwaysTranslate) {
+        if (alwaysTranslate) {
+            mAlwaysLanguages.add(language);
+        } else if (!mAlwaysLanguages.contains(language)) {
+            mAlwaysLanguages.remove(language);
+        }
+    }
+
+    @Override
+    public void getNeverTranslateLanguages(List<String> list) {
+        list.addAll(mNeverLanguages);
+    }
+
+    @Override
+    public void setLanguageBlockedState(String language, boolean blocked) {
+        if (blocked) {
+            mNeverLanguages.add(language);
+        } else {
+            mNeverLanguages.remove(language);
+        }
+    }
+
+    @Override
+    public boolean isBlockedLanguage(String language) {
+        return mNeverLanguages.contains(language);
+    }
+
+    /**
+     * Following methods are not implemented yet since they are not needed by current tests.
+     */
+
+    @Override
+    public void manualTranslateWhenReady(WebContents webContents) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void translateToLanguage(WebContents webContents, String targetLanguageCode) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean canManuallyTranslate(WebContents webContents, boolean menuLogging) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean shouldShowManualTranslateIPH(WebContents webContents) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setPredefinedTargetLanguage(WebContents webContents, String targetLanguage) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getSourceLanguage(WebContents webContents) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCurrentLanguage(WebContents webContents) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void getModelLanguages(LinkedHashSet<String> set) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void moveAcceptLanguage(String language, int offset) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean getExplicitLanguageAskPromptShown() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setExplicitLanguageAskPromptShown(boolean shown) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setIgnoreMissingKeyForTesting(boolean ignore) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Extra utility functions for MockTranslateBridge
+     */
+
+    public int getChromeLanguagesCount() {
+        return mChromeLanguages.size();
+    }
+
+    public int getAlwaysLanguagesCount() {
+        return mAlwaysLanguages.size();
+    }
+
+    public int getNeverLanguagesCount() {
+        return mNeverLanguages.size();
+    }
+
+    /**
+     * Create a simple list of nine LanguageItems that are all possible Chrome languages
+     * representing combinations of available UI and translateable languages.
+     * The order or languages is: en, en-US, en-GB, hi, sw, xh, wa, af, and fil.
+     *  - UI Languages: af, fil, en-US, en-GB, hi, sw
+     *  - Translateable Languages: af, en, fil, hi, sw, xh
+     * @return List of LanguageItems.
+     */
+    public static List<LanguageItem> getSimpleLanguageItemList() {
+        ArrayList<LanguageItem> languages = new ArrayList<>();
+        languages.add(new LanguageItem("en", "English", "English", true));
+        languages.add(new LanguageItem(
+                "en-US", "English (United States)", "English (United States)", true));
+        languages.add(new LanguageItem(
+                "en-GB", "English (United Kingdom)", "English (United Kingdom)", true));
+        languages.add(new LanguageItem("hi", "Hindi", "हिन्दी", true));
+        languages.add(new LanguageItem("sw", "Swahili", "Kiswahili", true));
+        languages.add(new LanguageItem("xh", "Xhosa", "isiXhosa", true));
+        languages.add(new LanguageItem("wa", "Walloon", "Walloon", false));
+        languages.add(new LanguageItem("af", "Afrikaans", "Afrikaans", true));
+        languages.add(new LanguageItem("fil", "Filipino", "Filipino", true));
+        return languages;
+    }
+}
diff --git a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/TranslateBridge.java b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/TranslateBridge.java
index b54d5912..4d0fd1d9 100644
--- a/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/TranslateBridge.java
+++ b/chrome/browser/language/android/java/src/org/chromium/chrome/browser/translate/TranslateBridge.java
@@ -270,7 +270,7 @@
     }
 
     @NativeMethods
-    interface Natives {
+    public interface Natives {
         void manualTranslateWhenReady(WebContents webContents);
         void translateToLanguage(WebContents webContents, String targetLanguageCode);
         boolean canManuallyTranslate(WebContents webContents, boolean menuLogging);
diff --git a/chrome/browser/mac/DIR_METADATA b/chrome/browser/mac/DIR_METADATA
deleted file mode 100644
index d182185..0000000
--- a/chrome/browser/mac/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index b3df3b2..ef9b742d 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -560,7 +560,7 @@
               // invocation of this callback.
               network::mojom::NetworkService* network_service =
                   content::GetNetworkService();
-              network_service->SetPreloadedFirstPartySets(raw_sets);
+              network_service->SetFirstPartySets(raw_sets);
             }));
   }
 
diff --git a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/DIR_METADATA b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/DIR_METADATA
index 760bca7..7a2580a 100644
--- a/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/DIR_METADATA
+++ b/chrome/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "UI>Notifications"
-}
-team_email: "platform-capabilities@chromium.org"
 os: ANDROID
diff --git a/chrome/browser/notifications/scheduler/DIR_METADATA b/chrome/browser/notifications/scheduler/DIR_METADATA
deleted file mode 100644
index 5acb01e3..0000000
--- a/chrome/browser/notifications/scheduler/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Notifications"
-}
diff --git a/chrome/browser/optimization_guide/blink/DIR_METADATA b/chrome/browser/optimization_guide/blink/DIR_METADATA
deleted file mode 100644
index fb4428a..0000000
--- a/chrome/browser/optimization_guide/blink/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>OptimizationGuide"
-}
diff --git a/chrome/browser/page_load_metrics/integration_tests/DIR_METADATA b/chrome/browser/page_load_metrics/integration_tests/DIR_METADATA
index 9702949..77366ef 100644
--- a/chrome/browser/page_load_metrics/integration_tests/DIR_METADATA
+++ b/chrome/browser/page_load_metrics/integration_tests/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Speed>Metrics"
-}
 team_email: "speed-metrics-dev@chromium.org"
diff --git a/chrome/browser/page_load_metrics/observers/core/DIR_METADATA b/chrome/browser/page_load_metrics/observers/core/DIR_METADATA
deleted file mode 100644
index e80036e..0000000
--- a/chrome/browser/page_load_metrics/observers/core/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Speed>Metrics"
-}
diff --git a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java
index 727d408..8997af6 100644
--- a/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java
+++ b/chrome/browser/password_check/android/javatests/src/org/chromium/chrome/browser/password_check/PasswordCheckEditViewTest.java
@@ -51,6 +51,7 @@
 
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.password_manager.settings.ReauthenticationManager;
 import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
@@ -126,6 +127,7 @@
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/1210268")
     public void testSiteAndUsernameDisabled() {
         onView(withId(R.id.site_edit)).check(matches(allOf(not(isEnabled()), not(isFocusable()))));
         onView(withId(R.id.username_edit))
diff --git a/chrome/browser/password_manager/android/DIR_METADATA b/chrome/browser/password_manager/android/DIR_METADATA
deleted file mode 100644
index b420232..0000000
--- a/chrome/browser/password_manager/android/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "UI>Browser>Passwords"
-}
-team_email: "chromium-dev@chromium.org"
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 785e778..f01a6a7 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -1875,23 +1875,13 @@
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  // Skip Ad button is not displayed if video is not playing even if media
-  // session action handler has been set.
+  // Skip Ad button is displayed if a media session action handler has been set.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "setMediaSessionActionHandler('skipad');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
-      {GetOverlayWindow()->skip_ad_controls_view_for_testing()}, false));
-
-  // Play video and check that Skip Ad button is now displayed when video plays.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "ensureVideoIsPlaying();", &result));
-  ASSERT_TRUE(result);
-  EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
       {GetOverlayWindow()->skip_ad_controls_view_for_testing()}, true));
 
-  // Unset action handler and check that Skip Ad button is not displayed when
-  // video plays.
+  // Unset action handler and check that Skip Ad button is not displayed.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "unsetMediaSessionActionHandler('skipad');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
@@ -1919,10 +1909,6 @@
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
       {GetOverlayWindow()->play_pause_controls_view_for_testing()}, false));
 
-  // Play second video (non-muted) so that Media Session becomes active.
-  ASSERT_TRUE(
-      content::ExecuteScript(active_web_contents, "secondVideo.play();"));
-
   // Set Media Session action "play" handler and check that Play/Pause button
   // is still hidden.
   ASSERT_TRUE(content::ExecuteScript(active_web_contents,
@@ -1973,24 +1959,14 @@
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  // Next Track button is not displayed if video is not playing even if media
-  // session action handler has been set.
+  // Next Track button is displayed if a media session action handler has been
+  // set.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "setMediaSessionActionHandler('nexttrack');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
-      {GetOverlayWindow()->next_track_controls_view_for_testing()}, false));
-
-  // Play video and check that Next Track button is now displayed when video
-  // plays.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "ensureVideoIsPlaying();", &result));
-  ASSERT_TRUE(result);
-  EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
       {GetOverlayWindow()->next_track_controls_view_for_testing()}, true));
 
-  // Unset action handler and check that Next Track button is not displayed
-  // when video plays.
+  // Unset action handler and check that Next Track button is not displayed.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "unsetMediaSessionActionHandler('nexttrack');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
@@ -2011,24 +1987,14 @@
   content::WebContents* active_web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
 
-  // Previous Track button is not displayed if video is not playing even if
-  // media session action handler has been set.
+  // Previous Track button is displayed if a media session action handler has
+  // been set.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "setMediaSessionActionHandler('previoustrack');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
-      {GetOverlayWindow()->previous_track_controls_view_for_testing()}, false));
-
-  // Play video and check that Previous Track button is now displayed when
-  // video plays.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "ensureVideoIsPlaying();", &result));
-  ASSERT_TRUE(result);
-  EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
       {GetOverlayWindow()->previous_track_controls_view_for_testing()}, true));
 
-  // Unset action handler and check that Previous Track button is not displayed
-  // when video plays.
+  // Unset action handler and check that Previous Track button is not displayed.
   ASSERT_TRUE(content::ExecuteScript(
       active_web_contents, "unsetMediaSessionActionHandler('previoustrack');"));
   EXPECT_NO_FATAL_FAILURE(AssertControlsVisible(
diff --git a/chrome/browser/policy/messaging_layer/DIR_METADATA b/chrome/browser/policy/messaging_layer/DIR_METADATA
deleted file mode 100644
index f37723a..0000000
--- a/chrome/browser/policy/messaging_layer/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Enterprise"
-}
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DIR_METADATA b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DIR_METADATA
deleted file mode 100644
index 45d75af..0000000
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>Preferences"
-}
diff --git a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA b/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA
deleted file mode 100644
index a012b93..0000000
--- a/chrome/browser/profiles/android/java/src/org/chromium/chrome/browser/cookies/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
\ No newline at end of file
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index 3cf8640..dcc2d9e 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -167,7 +167,7 @@
     info->SetString(kAccountIdKey, params.account_id.GetAccountIdKey());
   info->SetBoolKey(prefs::kSignedInWithCredentialProvider,
                    params.is_signed_in_with_credential_provider);
-  cache->SetWithoutPathExpansion(key, std::move(info));
+  cache->SetKey(key, base::Value::FromUniquePtrValue(std::move(info)));
   ProfileAttributesEntry* entry = InitEntryWithKey(key, params.is_omitted);
   entry->InitializeLastNameToDisplay();
 
@@ -517,7 +517,7 @@
     std::unique_ptr<base::DictionaryValue> info) {
   DictionaryPrefUpdate update(prefs_, prefs::kProfileInfoCache);
   base::DictionaryValue* cache = update.Get();
-  cache->SetWithoutPathExpansion(keys_[index], std::move(info));
+  cache->SetKey(keys_[index], base::Value::FromUniquePtrValue(std::move(info)));
 }
 
 std::string ProfileInfoCache::CacheKeyFromProfilePath(
diff --git a/chrome/browser/renderer_context_menu/DIR_METADATA b/chrome/browser/renderer_context_menu/DIR_METADATA
deleted file mode 100644
index d182185..0000000
--- a/chrome/browser/renderer_context_menu/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/resources/chromeos/accessibility/braille_ime/DIR_METADATA b/chrome/browser/resources/chromeos/accessibility/braille_ime/DIR_METADATA
index a377c619..b03a4753 100644
--- a/chrome/browser/resources/chromeos/accessibility/braille_ime/DIR_METADATA
+++ b/chrome/browser/resources/chromeos/accessibility/braille_ime/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Accessibility>ChromeVox"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/DIR_METADATA b/chrome/browser/resources/chromeos/accessibility/chromevox/DIR_METADATA
index a377c619..b03a4753 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/DIR_METADATA
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Accessibility>ChromeVox"
 }
-team_email: "chromium-accessibility@chromium.org"
diff --git a/chrome/browser/resources/tools/optimize_webui.py b/chrome/browser/resources/tools/optimize_webui.py
index f41a89b..32c4bba3 100755
--- a/chrome/browser/resources/tools/optimize_webui.py
+++ b/chrome/browser/resources/tools/optimize_webui.py
@@ -258,12 +258,13 @@
 
   # Output a manifest file that will be used to auto-generate a grd file later.
   if args.out_manifest:
-    manifest_data = {}
-    manifest_data['base_dir'] = '%s' % args.out_folder
-    manifest_data['files'] = manifest.keys()
-    manifest_file = open(
-        os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'wb')
-    json.dump(manifest_data, manifest_file)
+    manifest_data = {
+      'base_dir': args.out_folder,
+      'files': list(manifest.keys()),
+    }
+    with open(os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'w') \
+        as manifest_file:
+      json.dump(manifest_data, manifest_file)
 
   _update_dep_file(args.input, args, manifest)
 
diff --git a/chrome/browser/safe_browsing/android/DIR_METADATA b/chrome/browser/safe_browsing/android/DIR_METADATA
deleted file mode 100644
index ee2d9cf5..0000000
--- a/chrome/browser/safe_browsing/android/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "Services>Safebrowsing"
-}
-team_email: "safebrowsing@chromium.org"
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/DIR_METADATA b/chrome/browser/safe_browsing/chrome_cleaner/DIR_METADATA
index 5078508f..156afab 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/DIR_METADATA
+++ b/chrome/browser/safe_browsing/chrome_cleaner/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail: {
   component: "Services>Safebrowsing>ChromeCleanup"
 }
-team_email: "safebrowsing@chromium.org"
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index 2d799f78..a4f51bbe 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -692,6 +692,55 @@
   std::move(cb).Run("fake_access_token");
 }
 
+TEST_F(ClientSideDetectionHostTest,
+       PhishingDetectionDoneCalledTwiceShouldSucceed) {
+  SetEnhancedProtectionPrefForTests(profile()->GetPrefs(), true);
+  SetFeatures(
+      /*enable_features*/ {kClientSideDetectionWithToken},
+      /*disable_features*/ {});
+
+  ClientPhishingRequest verdict;
+  verdict.set_url("http://example.com/");
+  verdict.set_client_score(1.0f);
+  verdict.set_is_phishing(true);
+
+  // Set up mock call to csd service.
+  EXPECT_CALL(*csd_service_,
+              SendClientReportPhishingRequest(PartiallyEqualVerdict(verdict), _,
+                                              "fake_access_token_1"))
+      .Times(1);
+
+  // Set up mock call to csd service.
+  EXPECT_CALL(*csd_service_,
+              SendClientReportPhishingRequest(PartiallyEqualVerdict(verdict), _,
+                                              "fake_access_token_2"))
+      .Times(1);
+
+  // Set up mock call to token fetcher.
+  SafeBrowsingTokenFetcher::Callback cb;
+  EXPECT_CALL(*raw_token_fetcher_, Start(_))
+      .Times(1)
+      .WillRepeatedly(MoveArg<0>(&cb));
+
+  // Make the call.
+  PhishingDetectionDone(verdict.SerializeAsString());
+
+  // Wait for token fetcher to be called.
+  EXPECT_TRUE(Mock::VerifyAndClear(raw_token_fetcher_));
+
+  ASSERT_FALSE(cb.is_null());
+  std::move(cb).Run("fake_access_token_1");
+
+  // Make the call again.
+  EXPECT_CALL(*raw_token_fetcher_, Start(_))
+      .Times(1)
+      .WillRepeatedly(MoveArg<0>(&cb));
+  PhishingDetectionDone(verdict.SerializeAsString());
+  EXPECT_TRUE(Mock::VerifyAndClear(raw_token_fetcher_));
+  ASSERT_FALSE(cb.is_null());
+  std::move(cb).Run("fake_access_token_2");
+}
+
 TEST_F(ClientSideDetectionHostIncognitoTest,
        PhishingDetectionDoneIncognitoShouldNotHaveToken) {
   SetEnhancedProtectionPrefForTests(profile()->GetPrefs(), true);
diff --git a/chrome/browser/safe_browsing/download_protection/DIR_METADATA b/chrome/browser/safe_browsing/download_protection/DIR_METADATA
deleted file mode 100644
index 6015b06..0000000
--- a/chrome/browser/safe_browsing/download_protection/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Services>Safebrowsing"
-}
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
index d16da852..d46b351 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -1319,12 +1319,12 @@
       new base::DictionaryValue());
   auto type_dict = std::make_unique<base::DictionaryValue>();
   type_dict->SetKey("foo", base::Value("47"));
-  incidents_sent->SetWithoutPathExpansion(blocklist_load_type,
-                                          std::move(type_dict));
+  incidents_sent->SetKey(blocklist_load_type,
+                         base::Value::FromUniquePtrValue(std::move(type_dict)));
   type_dict = std::make_unique<base::DictionaryValue>();
   type_dict->SetKey("bar", base::Value("43"));
-  incidents_sent->SetWithoutPathExpansion(preference_type,
-                                          std::move(type_dict));
+  incidents_sent->SetKey(preference_type,
+                         base::Value::FromUniquePtrValue(std::move(type_dict)));
 
   // Add a profile.
   Profile* profile =
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/DIR_METADATA b/chrome/browser/safe_browsing/settings_reset_prompt/DIR_METADATA
index bf59213..427a0a7 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/DIR_METADATA
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/DIR_METADATA
@@ -1,4 +1 @@
-monorail: {
-  component: "Services>Safebrowsing"
-}
 team_email: "security-dev@chromium.org"
diff --git a/chrome/browser/search/suggestions/DIR_METADATA b/chrome/browser/search/suggestions/DIR_METADATA
deleted file mode 100644
index 4c751468..0000000
--- a/chrome/browser/search/suggestions/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "UI>Browser>NewTabPage"
-}
-team_email: "ntp-dev@chromium.org"
diff --git a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/DIR_METADATA b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/DIR_METADATA
index d867703..7a2580a 100644
--- a/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/DIR_METADATA
+++ b/chrome/browser/search_engines/android/java/src/org/chromium/chrome/browser/search_engines/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Search"
-}
 os: ANDROID
diff --git a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA b/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA
deleted file mode 100644
index 221823e82..0000000
--- a/chrome/browser/share/android/java/src/org/chromium/chrome/browser/share/send_tab_to_self/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser>Sharing"
-}
diff --git a/chrome/browser/sharesheet/sharesheet_service_delegate.cc b/chrome/browser/sharesheet/sharesheet_service_delegate.cc
index 34f24f5b..f250b1b 100644
--- a/chrome/browser/sharesheet/sharesheet_service_delegate.cc
+++ b/chrome/browser/sharesheet/sharesheet_service_delegate.cc
@@ -20,8 +20,7 @@
     SharesheetService* sharesheet_service)
     : native_window_(native_window),
       sharesheet_bubble_view_(
-          std::make_unique<ash::sharesheet::SharesheetBubbleView>(native_window,
-                                                                  this)),
+          new ash::sharesheet::SharesheetBubbleView(native_window, this)),
       sharesheet_service_(sharesheet_service) {}
 
 SharesheetServiceDelegate::~SharesheetServiceDelegate() = default;
@@ -61,7 +60,6 @@
 
 void SharesheetServiceDelegate::OnBubbleClosed(
     const std::u16string& active_action) {
-  sharesheet_bubble_view_.release();
   sharesheet_service_->OnBubbleClosed(native_window_, active_action);
   // This object is now deleted and nothing can be accessed any more.
   // Therefore there is no need to set is_bubble_open_ to false.
diff --git a/chrome/browser/sharesheet/sharesheet_service_delegate.h b/chrome/browser/sharesheet/sharesheet_service_delegate.h
index 276030f..24dc55a 100644
--- a/chrome/browser/sharesheet/sharesheet_service_delegate.h
+++ b/chrome/browser/sharesheet/sharesheet_service_delegate.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_SHARESHEET_SHARESHEET_SERVICE_DELEGATE_H_
 #define CHROME_BROWSER_SHARESHEET_SHARESHEET_SERVICE_DELEGATE_H_
 
-#include <memory>
 #include <string>
 
 #include "base/callback.h"
@@ -77,8 +76,8 @@
   gfx::NativeWindow native_window_;
 
   std::u16string active_action_;
-  std::unique_ptr<ash::sharesheet::SharesheetBubbleView>
-      sharesheet_bubble_view_;
+  // Owned by views.
+  ash::sharesheet::SharesheetBubbleView* sharesheet_bubble_view_;
   SharesheetService* sharesheet_service_;
 };
 
diff --git a/chrome/browser/signin/services/DIR_METADATA b/chrome/browser/signin/services/DIR_METADATA
index c22824a1..7a2580a 100644
--- a/chrome/browser/signin/services/DIR_METADATA
+++ b/chrome/browser/signin/services/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "Services>SignIn"
-}
-team_email: "chrome-signin@chromium.org"
 os: ANDROID
diff --git a/chrome/browser/signin/ui/DIR_METADATA b/chrome/browser/signin/ui/DIR_METADATA
index c22824a1..7a2580a 100644
--- a/chrome/browser/signin/ui/DIR_METADATA
+++ b/chrome/browser/signin/ui/DIR_METADATA
@@ -1,5 +1 @@
-monorail {
-  component: "Services>SignIn"
-}
-team_email: "chrome-signin@chromium.org"
 os: ANDROID
diff --git a/chrome/browser/signin/ui/android/BUILD.gn b/chrome/browser/signin/ui/android/BUILD.gn
index 9cefcf7..f57c50e8 100644
--- a/chrome/browser/signin/ui/android/BUILD.gn
+++ b/chrome/browser/signin/ui/android/BUILD.gn
@@ -28,6 +28,7 @@
     "//components/signin/public/android:java",
     "//components/user_prefs/android:java",
     "//content/public/android:content_java",
+    "//third_party/android_deps:guava_android_java",
     "//third_party/androidx:androidx_annotation_annotation_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
     "//third_party/androidx:androidx_appcompat_appcompat_resources_java",
@@ -146,6 +147,7 @@
     "//components/signin/public/android:signin_java_test_support",
     "//components/user_prefs/android:java",
     "//content/public/android:content_java",
+    "//third_party/android_deps:guava_android_java",
     "//third_party/android_deps:robolectric_all_java",
     "//third_party/androidx:androidx_appcompat_appcompat_java",
     "//third_party/androidx:androidx_fragment_fragment_java",
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtil.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtil.java
index 6f88fa5..c08e6a3 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtil.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtil.java
@@ -11,6 +11,9 @@
 
 import androidx.annotation.Nullable;
 
+import com.google.common.base.Optional;
+
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
@@ -78,13 +81,21 @@
             return false;
         }
 
-        final List<String> currentAccountNames =
-                AccountUtils.toAccountNames(accountManagerFacade.tryGetGoogleAccounts());
-        if (currentAccountNames.isEmpty()) {
+        final List<Account> accounts = accountManagerFacade.tryGetGoogleAccounts();
+
+        if (accounts.isEmpty()) {
             // Don't show if the account list isn't available yet or there are no accounts in it.
             return false;
         }
 
+        Optional<Boolean> isDefaultAccountSubjectToMinorModeRestrictions =
+                accountManagerFacade.isAccountSubjectToMinorModeRestrictions(accounts.get(0));
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.MINOR_MODE_SUPPORT)
+                && isDefaultAccountSubjectToMinorModeRestrictions.or(/* defaultValue= */ false)) {
+            return false;
+        }
+
+        final List<String> currentAccountNames = AccountUtils.toAccountNames(accounts);
         final Set<String> previousAccountNames = prefManager.getSigninPromoLastAccountNames();
         if (previousAccountNames != null && previousAccountNames.containsAll(currentAccountNames)) {
             // Don't show if no new accounts have been added after the last time promo was shown.
diff --git a/chrome/browser/signin/ui/android/junit/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtilLaunchSigninPromoTest.java b/chrome/browser/signin/ui/android/junit/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtilLaunchSigninPromoTest.java
index a08cfff9..015e256e 100644
--- a/chrome/browser/signin/ui/android/junit/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtilLaunchSigninPromoTest.java
+++ b/chrome/browser/signin/ui/android/junit/src/org/chromium/chrome/browser/signin/ui/SigninPromoUtilLaunchSigninPromoTest.java
@@ -6,14 +6,18 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.accounts.Account;
 import android.content.Context;
 
+import com.google.common.base.Optional;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -27,10 +31,12 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.JniMocker;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
+import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.prefs.PrefService;
 import org.chromium.components.signin.base.CoreAccountInfo;
@@ -47,6 +53,7 @@
  * Tests for {@link SigninPromoUtil#launchSigninPromoIfNeeded}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
+@Features.EnableFeatures({ChromeFeatureList.MINOR_MODE_SUPPORT})
 public class SigninPromoUtilLaunchSigninPromoTest {
     private static final int CURRENT_MAJOR_VERSION = 42;
     @Rule
@@ -55,6 +62,9 @@
     @Rule
     public final JniMocker mocker = new JniMocker();
 
+    @Rule
+    public final Features.JUnitProcessor processor = new Features.JUnitProcessor();
+
     private final FakeAccountManagerFacade mFakeAccountManagerFacade =
             spy(new FakeAccountManagerFacade(null));
 
@@ -211,4 +221,38 @@
         Assert.assertEquals(40, mPrefManager.getSigninPromoLastShownVersion());
         Assert.assertEquals(2, mPrefManager.getSigninPromoLastAccountNames().size());
     }
+
+    @Test
+    public void promoHiddenWhenDefaultAccountIsMinor() {
+        mPrefManager.setSigninPromoLastShownVersion(38);
+        mAccountManagerTestRule.addAccount("test2@gmail.com");
+        doAnswer(invocation -> {
+            final Account account = invocation.getArgument(0);
+            return Optional.of(AccountManagerTestRule.TEST_ACCOUNT_EMAIL.equals(account.name));
+        })
+                .when(mFakeAccountManagerFacade)
+                .isAccountSubjectToMinorModeRestrictions(any());
+
+        Assert.assertFalse(SigninPromoUtil.launchSigninPromoIfNeeded(
+                mContext, mLauncherMock, CURRENT_MAJOR_VERSION));
+
+        verify(mLauncherMock, never()).launchActivityIfAllowed(any(), anyInt());
+    }
+
+    @Test
+    public void promoVisibleWhenTheSecondaryAccountIsMinor() {
+        final CoreAccountInfo secondAccount = mAccountManagerTestRule.addAccount("test2@gmail.com");
+        mPrefManager.setSigninPromoLastShownVersion(38);
+        doAnswer(invocation -> {
+            final Account account = invocation.getArgument(0);
+            return Optional.of(secondAccount.getEmail().equals(account.name));
+        })
+                .when(mFakeAccountManagerFacade)
+                .isAccountSubjectToMinorModeRestrictions(any());
+
+        Assert.assertTrue(SigninPromoUtil.launchSigninPromoIfNeeded(
+                mContext, mLauncherMock, CURRENT_MAJOR_VERSION));
+
+        verify(mLauncherMock).launchActivityIfAllowed(mContext, SigninAccessPoint.SIGNIN_PROMO);
+    }
 }
diff --git a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
index 0fdf1c18..84fa358d8 100644
--- a/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
+++ b/chrome/browser/supervised_user/child_accounts/family_info_fetcher_unittest.cc
@@ -58,8 +58,10 @@
   std::unique_ptr<base::DictionaryValue> profile_dict =
       std::make_unique<base::DictionaryValue>();
   profile_dict->SetKey("name", base::Value(family.name));
-  family_dict->SetWithoutPathExpansion("profile", std::move(profile_dict));
-  dict.SetWithoutPathExpansion("family", std::move(family_dict));
+  family_dict->SetKey("profile",
+                      base::Value::FromUniquePtrValue(std::move(profile_dict)));
+  dict.SetKey("family",
+              base::Value::FromUniquePtrValue(std::move(family_dict)));
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
@@ -67,8 +69,7 @@
 
 std::string BuildEmptyGetFamilyProfileResponse() {
   base::DictionaryValue dict;
-  dict.SetWithoutPathExpansion("family",
-                               std::make_unique<base::DictionaryValue>());
+  dict.SetKey("family", base::DictionaryValue());
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
@@ -100,11 +101,12 @@
         profile_dict->SetKey("profileImageUrl",
                              base::Value(member.profile_image_url));
 
-      member_dict->SetWithoutPathExpansion("profile", std::move(profile_dict));
+      member_dict->SetKey(
+          "profile", base::Value::FromUniquePtrValue(std::move(profile_dict)));
     }
     list->Append(std::move(member_dict));
   }
-  dict.SetWithoutPathExpansion("members", std::move(list));
+  dict.SetKey("members", base::Value::FromUniquePtrValue(std::move(list)));
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
index 5e56ad14..6a2758a 100644
--- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
+++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -29,7 +29,8 @@
   base::DictionaryValue dict;
   auto permission_dict = std::make_unique<base::DictionaryValue>();
   permission_dict->SetKey("id", base::Value("requestid"));
-  dict.SetWithoutPathExpansion("permissionRequest", std::move(permission_dict));
+  dict.SetKey("permissionRequest",
+              base::Value::FromUniquePtrValue(std::move(permission_dict)));
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
diff --git a/chrome/browser/supervised_user/supervised_user_settings_service.cc b/chrome/browser/supervised_user/supervised_user_settings_service.cc
index 3fd9201..6217f719 100644
--- a/chrome/browser/supervised_user/supervised_user_settings_service.cc
+++ b/chrome/browser/supervised_user/supervised_user_settings_service.cc
@@ -160,14 +160,15 @@
     base::RecordAction(UserMetricsAction("ManagedUsers_UploadItem_Queued"));
     dict = GetQueuedItems();
   }
-  dict->SetWithoutPathExpansion(key_suffix, std::move(value));
+  dict->SetKey(key_suffix, base::Value::FromUniquePtrValue(std::move(value)));
 }
 
 void SupervisedUserSettingsService::SetLocalSetting(
     const std::string& key,
     std::unique_ptr<base::Value> value) {
   if (value)
-    local_settings_->SetWithoutPathExpansion(key, std::move(value));
+    local_settings_->SetKey(key,
+                            base::Value::FromUniquePtrValue(std::move(value)));
   else
     local_settings_->RemoveKey(key);
 
@@ -241,7 +242,7 @@
     std::unique_ptr<base::Value> value =
         JSONReader::ReadDeprecated(supervised_user_setting.value());
     // Wrongly formatted input will cause null values.
-    // SetWithoutPathExpansion below requires non-null values.
+    // SetKey below requires non-null values.
     if (!value) {
       DLOG(ERROR) << "Invalid managed user setting value: "
                   << supervised_user_setting.value()
@@ -251,7 +252,8 @@
     std::string name_suffix = supervised_user_setting.name();
     std::string name_key = name_suffix;
     base::DictionaryValue* dict = GetDictionaryAndSplitKey(&name_suffix);
-    dict->SetWithoutPathExpansion(name_suffix, std::move(value));
+    dict->SetKey(name_suffix,
+                 base::Value::FromUniquePtrValue(std::move(value)));
     if (seen_keys.find(name_key) == seen_keys.end()) {
       added_sync_keys.insert(name_key);
     }
@@ -342,7 +344,7 @@
           DLOG_IF(WARNING, change_type == SyncChange::ACTION_UPDATE)
               << "Value for key " << key << " doesn't exist yet";
         }
-        dict->SetWithoutPathExpansion(key, std::move(value));
+        dict->SetKey(key, base::Value::FromUniquePtrValue(std::move(value)));
         break;
       }
       case SyncChange::ACTION_DELETE: {
diff --git a/chrome/browser/tab_contents/DIR_METADATA b/chrome/browser/tab_contents/DIR_METADATA
deleted file mode 100644
index d182185..0000000
--- a/chrome/browser/tab_contents/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/touch_to_fill/android/DIR_METADATA b/chrome/browser/touch_to_fill/android/DIR_METADATA
deleted file mode 100644
index 17b7d3f..0000000
--- a/chrome/browser/touch_to_fill/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser>Passwords"
-}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index e19181c6..bf4821d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1844,6 +1844,8 @@
       "app_list/search/ranking/ranker_delegate.h",
       "app_list/search/ranking/score_normalizing_ranker.cc",
       "app_list/search/ranking/score_normalizing_ranker.h",
+      "app_list/search/ranking/top_match_ranker.cc",
+      "app_list/search/ranking/top_match_ranker.h",
       "app_list/search/score_normalizer/balanced_reservoir.cc",
       "app_list/search/score_normalizer/balanced_reservoir.h",
       "app_list/search/score_normalizer/score_normalizer.cc",
diff --git a/chrome/browser/ui/DIR_METADATA b/chrome/browser/ui/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/DIR_METADATA b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/DIR_METADATA
deleted file mode 100644
index 31157b6a..0000000
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/load_progress/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Toolbar"
-}
-os: ANDROID
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h
deleted file mode 100644
index f862d58b..0000000
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2015 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_UI_APP_LIST_SEARCH_LAUNCHER_SEARCH_LAUNCHER_SEARCH_PROVIDER_H_
-#define CHROME_BROWSER_UI_APP_LIST_SEARCH_LAUNCHER_SEARCH_LAUNCHER_SEARCH_PROVIDER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/search/launcher_search/launcher_search_result.h"
-#include "chrome/browser/ui/app_list/search/search_provider.h"
-#include "chromeos/components/string_matching/tokenized_string.h"
-#include "extensions/common/extension_id.h"
-
-namespace app_list {
-
-// LauncherSearchProvider dispatches queries to extensions and fetches the
-// results from them via chrome.launcherSearchProvider API.
-// TODO(crbug.com/1188495): This provider is no longer used and should be
-// cleaned up.
-class LauncherSearchProvider : public SearchProvider {
- public:
-  explicit LauncherSearchProvider(Profile* profile);
-  ~LauncherSearchProvider() override;
-
-  void Start(const std::u16string& query) override;
-  void SetSearchResults(
-      const extensions::ExtensionId& extension_id,
-      std::vector<std::unique_ptr<LauncherSearchResult>> extension_results);
-  ash::AppListSearchResultType ResultType() override;
-
- private:
-  // Delays query for |kLauncherSearchProviderQueryDelayInMs|. This dispatches
-  // the latest query after no more calls to Start() for the delay duration.
-  void DelayQuery(base::OnceClosure closure);
-
-  // Dispatches |query| to LauncherSearchProvider service.
-  void StartInternal(const std::u16string& query);
-
-  // The search results of each extension.
-  std::map<extensions::ExtensionId,
-           std::vector<std::unique_ptr<LauncherSearchResult>>>
-      extension_results_;
-
-  // A timer to delay query.
-  base::OneShotTimer query_timer_;
-
-  // The timestamp of the last query.
-  base::Time last_query_time_;
-
-  base::TimeTicks query_start_time_;
-
-  absl::optional<chromeos::string_matching::TokenizedString>
-      last_tokenized_query_;
-
-  // The reference to profile to get LauncherSearchProvider service.
-  Profile* profile_;
-
-  base::WeakPtrFactory<LauncherSearchProvider> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(LauncherSearchProvider);
-};
-
-}  // namespace app_list
-
-#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_LAUNCHER_SEARCH_LAUNCHER_SEARCH_PROVIDER_H_
diff --git a/chrome/browser/ui/app_list/search/ranking/category_ranker.cc b/chrome/browser/ui/app_list/search/ranking/category_ranker.cc
index 415bfe00..76e7d3c 100644
--- a/chrome/browser/ui/app_list/search/ranking/category_ranker.cc
+++ b/chrome/browser/ui/app_list/search/ranking/category_ranker.cc
@@ -12,6 +12,10 @@
 namespace app_list {
 namespace {
 
+// The minimum value of a top match, as defined in top_match_ranker.cc.
+// TODO(crbug.com/1199206): Move these score constants into a common file.
+constexpr double kTopMatchMinScore = 1000.0;
+
 // The different categories of search result to display in launcher search.
 // Every search result type maps to one category. These values are not stable,
 // and should not be used for metrics.
@@ -138,6 +142,11 @@
   DCHECK(it != results.end());
   for (const auto& result : it->second) {
     const double old_relevance = result->relevance();
+
+    // Don't change the score of top matches.
+    if (old_relevance >= kTopMatchMinScore)
+      continue;
+
     DCHECK(0.0 <= old_relevance && old_relevance <= 1);
     const auto category = ResultTypeToCategory(result->result_type());
     const double new_relevance = 10 * category_ranks_[category] + old_relevance;
diff --git a/chrome/browser/ui/app_list/search/ranking/ranker.h b/chrome/browser/ui/app_list/search/ranking/ranker.h
index 6b300bb..99aefe7 100644
--- a/chrome/browser/ui/app_list/search/ranking/ranker.h
+++ b/chrome/browser/ui/app_list/search/ranking/ranker.h
@@ -26,6 +26,10 @@
   // Called each time a search provider sets new results. Passed the |provider|
   // type that triggered this call, and all |results| received so far for this
   // search session.
+  //
+  // The results for a provider can be updated more than once in a search
+  // session, which will invalidate pointers to previous results. It is
+  // recommended that rankers don't explicitly store any result pointers.
   virtual void Rank(ResultsMap& results, ProviderType provider) {}
 
   // Called each time a user launches a result.
diff --git a/chrome/browser/ui/app_list/search/ranking/top_match_ranker.cc b/chrome/browser/ui/app_list/search/ranking/top_match_ranker.cc
new file mode 100644
index 0000000..d221b21da
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/ranking/top_match_ranker.cc
@@ -0,0 +1,88 @@
+// 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/search/ranking/top_match_ranker.h"
+
+#include <vector>
+
+#include "chrome/browser/ui/app_list/search/chrome_search_result.h"
+
+namespace app_list {
+namespace {
+
+// The maximum number of top matches to show.
+constexpr size_t kNumTopMatches = 3u;
+
+// The score threshold before we consider a result a top match.
+constexpr double kTopMatchThreshold = 0.9;
+
+// The score added to a results relevance to make it a top match.
+constexpr double kScoreBoost = 1000.0;
+
+// Returns true if the |type| provider's results should never be a top match.
+bool ShouldIgnoreProvider(ProviderType type) {
+  switch (type) {
+      // Low-intent providers:
+    case ProviderType::kPlayStoreReinstallApp:
+    case ProviderType::kPlayStoreApp:
+      // Deprecated providers:
+    case ProviderType::kLauncher:
+    case ProviderType::kAnswerCard:
+      // Suggestion chip results:
+    case ProviderType::kFileChip:
+    case ProviderType::kDriveChip:
+    case ProviderType::kAssistantChip:
+      // Internal results:
+    case ProviderType::kUnknown:
+    case ProviderType::kInternalPrivacyInfo:
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace
+
+TopMatchRanker::TopMatchRanker() {}
+
+TopMatchRanker::~TopMatchRanker() {}
+
+void TopMatchRanker::Rank(ResultsMap& results, ProviderType provider) {
+  const auto it = results.find(provider);
+  DCHECK(it != results.end());
+
+  // TODO(crbug.com/1199206): This is an inefficient way of setting the top
+  // matches. Once we have category support built in to the ChromeSearchResult
+  // type this should be simplified.
+
+  // Early exit for providers we don't include in the top matches.
+  if (ShouldIgnoreProvider(provider))
+    return;
+
+  // Build a vector of all current matches. At the same time, reset the top
+  // match list by removing the score boost from any results that have it
+  // currently.
+  std::vector<std::pair<ChromeSearchResult*, double>> top_results;
+  for (const auto& type_results : results) {
+    for (const auto& result : type_results.second) {
+      const double current_score = result->relevance();
+      if (current_score >= kScoreBoost)
+        result->set_relevance(current_score - kScoreBoost);
+      if (current_score >= kTopMatchThreshold)
+        top_results.push_back({result.get(), current_score});
+    }
+  }
+
+  // Sort |top_results| best-to-worst.
+  std::sort(top_results.begin(), top_results.end(),
+            [](const auto& a, const auto& b) { return a.second > b.second; });
+
+  // Apply a score boost to at most the top |kNumTopMatches| results.
+  for (int i = 0; i < std::min(kNumTopMatches, top_results.size()); ++i) {
+    const double current_score = top_results[i].second;
+    top_results[i].first->set_relevance(kScoreBoost + current_score);
+  }
+}
+
+}  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/ranking/top_match_ranker.h b/chrome/browser/ui/app_list/search/ranking/top_match_ranker.h
new file mode 100644
index 0000000..ec0ba31
--- /dev/null
+++ b/chrome/browser/ui/app_list/search/ranking/top_match_ranker.h
@@ -0,0 +1,35 @@
+// 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_UI_APP_LIST_SEARCH_RANKING_TOP_MATCH_RANKER_H_
+#define CHROME_BROWSER_UI_APP_LIST_SEARCH_RANKING_TOP_MATCH_RANKER_H_
+
+#include "chrome/browser/ui/app_list/search/ranking/ranker.h"
+
+namespace app_list {
+
+// A ranker that inspects the scores of incoming results and picks out some of
+// them to become 'top matches' to be moved to the top of the results list.
+//
+// Choosing top matches is done by simply thresholding the scores of incoming
+// results. It is assumed that this runs after scores have been transformed to a
+// near-uniform distribution per-provider by the ScoreNormalizingRanker, and so
+// a score of 0.95 indicates a 95th percentile result from a provider, for
+// example. It is also assumed that this runs before the category ranker, which
+// moves the scores out of the normalized range [0,1].
+class TopMatchRanker : public Ranker {
+ public:
+  TopMatchRanker();
+  ~TopMatchRanker() override;
+
+  TopMatchRanker(const TopMatchRanker&) = delete;
+  TopMatchRanker& operator=(const TopMatchRanker&) = delete;
+
+  // Ranker:
+  void Rank(ResultsMap& results, ProviderType provider) override;
+};
+
+}  // namespace app_list
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_SEARCH_RANKING_TOP_MATCH_RANKER_H_
diff --git a/chrome/browser/ui/app_list/search/search_controller_impl_new.cc b/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
index d4b4dd8c..a9ad477 100644
--- a/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_impl_new.cc
@@ -107,6 +107,7 @@
 
   last_query_ = query;
   results_.clear();
+  ranker_->Start();
   for (const auto& provider : providers_)
     provider->Start(query);
 }
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_constants.h b/chrome/browser/ui/ash/sharesheet/sharesheet_constants.h
index 1dd7318..d1df80d 100644
--- a/chrome/browser/ui/ash/sharesheet/sharesheet_constants.h
+++ b/chrome/browser/ui/ash/sharesheet/sharesheet_constants.h
@@ -34,6 +34,7 @@
 constexpr int kImagePreviewCornerRadius = 4;
 constexpr int kImagePreviewIconCornerRadius = 2;
 constexpr int kImagePreviewPlaceholderIconContentSize = 20;
+constexpr SkAlpha kImagePreviewBackgroundAlphaComponent = 0x32;
 constexpr SkColor kImagePreviewPlaceholderBackgroundColor = gfx::kGoogleBlue050;
 
 constexpr int kHeaderViewBetweenChildSpacing = 12;
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
index 94bbd2ae..12d20af9 100644
--- a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
+++ b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.cc
@@ -34,7 +34,6 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/metadata/metadata_impl_macros.h"
-#include "ui/compositor/layer.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/image/image.h"
@@ -50,17 +49,12 @@
 
 // Concatenates all the strings in |file_names| with a comma delineator.
 const std::u16string ConcatenateFileNames(
-    const std::vector<std::string>& file_names) {
-  auto all_file_names = base::JoinString(file_names, ", ");
-  return base::ASCIIToUTF16(all_file_names);
+    const std::vector<std::u16string>& file_names) {
+  return base::JoinString(file_names, u", ");
 }
 
-gfx::ImageSkia CreateMimeTypeIcon(const gfx::VectorIcon& icon,
+gfx::ImageSkia CreateMimeTypeIcon(const gfx::ImageSkia& file_type_icon,
                                   const gfx::Size& image_size) {
-  gfx::ImageSkia file_type_icon = gfx::CreateVectorIcon(
-      icon, ash::sharesheet::kImagePreviewPlaceholderIconContentSize,
-      ash::ColorProvider::Get()->GetContentLayerColor(
-          ash::ColorProvider::ContentLayerType::kIconColorProminent));
   return ash::HoldingSpaceImage::SuperimposeOverEmptyImage(file_type_icon,
                                                            image_size);
 }
@@ -94,16 +88,14 @@
  public:
   METADATA_HEADER(SharesheetImagePreview);
   explicit SharesheetImagePreview(size_t file_count) {
-    SetPaintToLayer();
-    layer()->SetRoundedCornerRadius(
-        gfx::RoundedCornersF(kImagePreviewCornerRadius));
+    SetBackground(views::CreateRoundedRectBackground(
+        SK_ColorWHITE, kImagePreviewCornerRadius));
     SetLayoutManager(std::make_unique<views::BoxLayout>(
         views::BoxLayout::Orientation::kVertical,
         /* inside_border_insets */ gfx::Insets(),
         /* between_child_spacing */ kImagePreviewBetweenChildSpacing,
         /* collapse_margins_spacing */ false));
     SetPreferredSize(kImagePreviewFullSize);
-    SetBackground(views::CreateSolidBackground(SK_ColorWHITE));
     SetFocusBehavior(View::FocusBehavior::NEVER);
 
     size_t grid_icon_count =
@@ -132,12 +124,13 @@
         auto* label =
             children()[1]->AddChildView(std::make_unique<views::Label>(
                 base::StrCat({u"+", base::NumberToString16(enumeration)}),
-                CONTEXT_DOWNLOAD_SHELF_STATUS, ash::STYLE_SHARESHEET));
+                CONTEXT_DOWNLOAD_SHELF_STATUS, STYLE_SHARESHEET));
         label->SetLineHeight(kImagePreviewFileEnumerationLineHeight);
         label->SetEnabledColor(kButtonTextColor);
         label->SetHorizontalAlignment(gfx::ALIGN_CENTER);
-        label->SetBackground(views::CreateSolidBackground(
-            kImagePreviewPlaceholderBackgroundColor));
+        label->SetBackground(views::CreateRoundedRectBackground(
+            kImagePreviewPlaceholderBackgroundColor,
+            kImagePreviewIconCornerRadius));
         label->SetPreferredSize(kImagePreviewQuarterSize);
         return;
       }
@@ -159,6 +152,13 @@
 
   const size_t GetImageViewCount() { return image_views_.size(); }
 
+  void SetBackgroundColorForIndex(const int index, const SkColor& color) {
+    auto alpha_color =
+        SkColorSetA(color, kImagePreviewBackgroundAlphaComponent);
+    image_views_[index]->SetBackground(views::CreateRoundedRectBackground(
+        alpha_color, kImagePreviewIconCornerRadius));
+  }
+
  private:
   void AddRowToImageContainerView() {
     auto* row = AddChildView(std::make_unique<views::View>());
@@ -173,11 +173,6 @@
     auto* image_view =
         parent_view->AddChildView(std::make_unique<views::ImageView>());
     image_view->SetImageSize(size);
-    image_view->SetBackground(
-        views::CreateSolidBackground(kImagePreviewPlaceholderBackgroundColor));
-    image_view->SetPaintToLayer();
-    image_view->layer()->SetRoundedCornerRadius(
-        gfx::RoundedCornersF(kImagePreviewIconCornerRadius));
     image_views_.push_back(image_view);
   }
 
@@ -250,8 +245,14 @@
       ResolveImages();
     } else {
       DCHECK_GT(image_preview_->GetImageViewCount(), 0);
+      const auto icon_color = ColorProvider::Get()->GetContentLayerColor(
+          ColorProvider::ContentLayerType::kIconColorProminent);
+      gfx::ImageSkia file_type_icon = gfx::CreateVectorIcon(
+          GetTextVectorIcon(),
+          sharesheet::kImagePreviewPlaceholderIconContentSize, icon_color);
       image_preview_->GetImageViewAt(0)->SetImage(
-          CreateMimeTypeIcon(GetTextVectorIcon(), kImagePreviewFullSize));
+          CreateMimeTypeIcon(file_type_icon, kImagePreviewFullSize));
+      image_preview_->SetBackgroundColorForIndex(0, icon_color);
     }
   }
 }
@@ -268,13 +269,14 @@
 
   std::u16string filenames_tooltip_text = u"";
   if (intent_->file_urls.has_value() && !intent_->file_urls.value().empty()) {
-    std::vector<std::string> file_names;
+    std::vector<std::u16string> file_names;
     for (const auto& file_url : intent_->file_urls.value()) {
-      file_names.push_back(file_url.ExtractFileName());
+      const auto& file_path = GetFilePathFromFileSystemUrl(file_url);
+      file_names.push_back(file_path.BaseName().LossyDisplayName());
     }
     std::u16string file_text;
     if (file_names.size() == 1) {
-      file_text = base::ASCIIToUTF16(file_names[0]);
+      file_text = file_names[0];
     } else {
       // If there is more than 1 file, show an enumeration of the number of
       // files.
@@ -387,23 +389,27 @@
 }
 
 void SharesheetHeaderView::ResolveImage(size_t index) {
-  base::FilePath file_path;
-  storage::FileSystemContext* fs_context =
-      file_manager::util::GetFileManagerFileSystemContext(profile_);
-  storage::FileSystemURL fs_url =
-      fs_context->CrackURL(intent_->file_urls.value()[index]);
-  file_path = fs_url.path();
+  const auto& file_path =
+      GetFilePathFromFileSystemUrl(intent_->file_urls.value()[index]);
 
-  const auto size =
+  const auto& size =
       GetImagePreviewSize(index, intent_->file_urls.value().size());
   auto image = std::make_unique<HoldingSpaceImage>(
       size, file_path,
       base::BindRepeating(&SharesheetHeaderView::LoadImage,
                           weak_ptr_factory_.GetWeakPtr()),
-      absl::optional<gfx::ImageSkia>(
-          CreateMimeTypeIcon(chromeos::kFiletypeImageIcon, size)));
+      // We pass our own icon in here because we want the icon to appear
+      // while an image has not been loaded. If we didn't pass our own icon in,
+      // the container is left blank while we wait for an image to load.
+      absl::optional<gfx::ImageSkia>(CreateMimeTypeIcon(
+          GetIconForPath(file_path, /* dark_background= */ false), size)));
   DCHECK_GT(image_preview_->GetImageViewCount(), index);
   image_preview_->GetImageViewAt(index)->SetImage(image->GetImageSkia(size));
+  // TODO(crbug.com/2896003) Here and above, update this to check whether we're
+  // in dark mode or not.
+  const auto icon_color =
+      GetIconColorForPath(file_path, /* dark_background= */ false);
+  image_preview_->SetBackgroundColorForIndex(index, icon_color);
   image_subscription_.push_back(image->AddImageSkiaChangedCallback(
       base::BindRepeating(&SharesheetHeaderView::OnImageLoaded,
                           weak_ptr_factory_.GetWeakPtr(), size, index)));
@@ -427,6 +433,14 @@
       images_[index]->GetImageSkia(size));
 }
 
+const base::FilePath SharesheetHeaderView::GetFilePathFromFileSystemUrl(
+    const GURL& file_system_url) {
+  storage::FileSystemContext* fs_context =
+      file_manager::util::GetFileManagerFileSystemContext(profile_);
+  storage::FileSystemURL fs_url = fs_context->CrackURL(file_system_url);
+  return fs_url.path();
+}
+
 BEGIN_METADATA(SharesheetHeaderView, views::View)
 END_METADATA
 
diff --git a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.h b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.h
index 505d8d4e..c03c8bb 100644
--- a/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.h
+++ b/chrome/browser/ui/ash/sharesheet/sharesheet_header_view.h
@@ -67,6 +67,9 @@
                  HoldingSpaceImage::BitmapCallback callback);
   void OnImageLoaded(const gfx::Size& size, size_t index);
 
+  const base::FilePath GetFilePathFromFileSystemUrl(
+      const GURL& file_system_url);
+
   // Contains the share title and text preview views.
   views::View* text_view_ = nullptr;
   SharesheetImagePreview* image_preview_;
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
index a6a938e..c13476c 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller.h
@@ -16,6 +16,7 @@
   virtual ~EditAddressProfileDialogController() = default;
 
   virtual std::u16string GetWindowTitle() const = 0;
+  virtual std::u16string GetOkButtonLabel() const = 0;
   virtual const AutofillProfile& GetProfileToEdit() const = 0;
   // Gets invoked when the user click either OK or Cancel buttons in the address
   // profile dialog. `decision` reflects which button has been clicked.
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
index 92ebca7..393bdf80f 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.cc
@@ -25,9 +25,11 @@
 
 void EditAddressProfileDialogControllerImpl::OfferEdit(
     const AutofillProfile& profile,
+    bool is_update,
     AutofillClient::AddressProfileSavePromptCallback
         address_profile_save_prompt_callback) {
   address_profile_to_edit_ = profile;
+  is_update_ = is_update;
   address_profile_save_prompt_callback_ =
       std::move(address_profile_save_prompt_callback);
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
@@ -39,7 +41,14 @@
 std::u16string EditAddressProfileDialogControllerImpl::GetWindowTitle() const {
   // TODO(crbug.com/1167060): Use internationalized string upon having final
   // strings.
-  return u"Save Address?";
+  return is_update_ ? u"Update Address?" : u"Save Address?";
+}
+
+std::u16string EditAddressProfileDialogControllerImpl::GetOkButtonLabel()
+    const {
+  // TODO(crbug.com/1167060): Use internationalized string upon having final
+  // strings.
+  return is_update_ ? u"Update" : u"Save";
 }
 
 const AutofillProfile&
diff --git a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
index 0b58b70..ed69c316 100644
--- a/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/edit_address_profile_dialog_controller_impl.h
@@ -29,14 +29,17 @@
   ~EditAddressProfileDialogControllerImpl() override;
 
   // Sets up the controller and offers to edit the |profile| before saving it.
-  // |address_profile_save_prompt_callback| will be invoked once the user makes
-  // a decision with respect to the offer-to-edit prompt.
+  // |is_update| indicates whether this edit dialog was triggered from a save or
+  // update prompt. |address_profile_save_prompt_callback| will be invoked once
+  // the user makes a decision with respect to the offer-to-edit prompt.
   void OfferEdit(const AutofillProfile& profile,
+                 bool is_update,
                  AutofillClient::AddressProfileSavePromptCallback
                      address_profile_save_prompt_callback);
 
   // EditAddressProfileDialogController:
   std::u16string GetWindowTitle() const override;
+  std::u16string GetOkButtonLabel() const override;
   const AutofillProfile& GetProfileToEdit() const override;
   void OnUserDecision(
       AutofillClient::SaveAddressProfileOfferUserDecision decision,
@@ -58,6 +61,10 @@
   // before saving.
   AutofillProfile address_profile_to_edit_;
 
+  // Whether accepting this Edit dialog will result in saving a new address or
+  // updating an existing one.
+  bool is_update_ = false;
+
   AutofillBubbleBase* edit_dialog_ = nullptr;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
diff --git a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
index f96a845..782cbab 100644
--- a/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_update_address_profile_bubble_controller_impl.cc
@@ -77,6 +77,7 @@
   EditAddressProfileDialogControllerImpl* controller =
       EditAddressProfileDialogControllerImpl::FromWebContents(web_contents());
   controller->OfferEdit(address_profile_,
+                        /*is_update=*/original_profile_.has_value(),
                         std::move(address_profile_save_prompt_callback_));
 }
 
diff --git a/chrome/browser/ui/cocoa/DIR_METADATA b/chrome/browser/ui/cocoa/DIR_METADATA
index 9b7d626..fe8dec4 100644
--- a/chrome/browser/ui/cocoa/DIR_METADATA
+++ b/chrome/browser/ui/cocoa/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser"
-}
 os: MAC
diff --git a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
index 46bf1ba5..b18b9bf 100644
--- a/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/credit_card_autofill_touch_bar_controller_unittest.mm
@@ -18,6 +18,7 @@
 #import "ui/base/cocoa/touch_bar_util.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/test/gfx_util.h"
 
 namespace {
 
@@ -28,8 +29,8 @@
 
 class MockAutofillPopupController : public autofill::AutofillPopupController {
  public:
-  MockAutofillPopupController() {
-    gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
+  MockAutofillPopupController()
+      : default_font_desc_setter_("Arial, Times New Roman, 15px") {
     suggestions_.push_back(
         autofill::Suggestion("bufflehead", "canvasback", "goldeneye", 1));
     suggestions_.push_back(
@@ -89,6 +90,7 @@
  private:
   int line_count_;
   std::vector<autofill::Suggestion> suggestions_;
+  gfx::ScopedDefaultFontDescription default_font_desc_setter_;
 };
 
 class CreditCardAutofillTouchBarControllerUnitTest : public CocoaTest {
diff --git a/chrome/browser/ui/commander/DIR_METADATA b/chrome/browser/ui/commander/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/commander/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/ui/frame/DIR_METADATA b/chrome/browser/ui/frame/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/frame/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/ui/views/DIR_METADATA b/chrome/browser/ui/views/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/views/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
index a1ad18ab..86fbfd924 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.cc
@@ -36,6 +36,9 @@
   SetLayoutManager(std::make_unique<views::FillLayout>());
   set_margins(ChromeLayoutProvider::Get()->GetInsetsMetric(
       views::InsetsMetric::INSETS_DIALOG));
+
+  SetTitle(controller_->GetWindowTitle());
+  SetButtonLabel(ui::DIALOG_BUTTON_OK, controller_->GetOkButtonLabel());
 }
 
 EditAddressProfileView::~EditAddressProfileView() = default;
@@ -54,12 +57,6 @@
   GetWidget()->Close();
 }
 
-std::u16string EditAddressProfileView::GetWindowTitle() const {
-  // |controller_| can be nullptr when the framework calls this method after a
-  // button click.
-  return controller_ ? controller_->GetWindowTitle() : std::u16string();
-}
-
 void EditAddressProfileView::WindowClosing() {
   if (controller_) {
     controller_->OnDialogClosed();
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view.h b/chrome/browser/ui/views/autofill/edit_address_profile_view.h
index d15928f7..51032d6 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view.h
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view.h
@@ -38,7 +38,6 @@
   void Hide() override;
 
   // views::DialogDelegateView
-  std::u16string GetWindowTitle() const override;
   void WindowClosing() override;
   void ChildPreferredSizeChanged(views::View* child) override;
 
diff --git a/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc b/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
index 15679cb..96c2c17 100644
--- a/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
+++ b/chrome/browser/ui/views/autofill/edit_address_profile_view_unittest.cc
@@ -31,6 +31,7 @@
     : public EditAddressProfileDialogController {
  public:
   MOCK_METHOD(std::u16string, GetWindowTitle, (), (const, override));
+  MOCK_METHOD(std::u16string, GetOkButtonLabel, (), (const, override));
   MOCK_METHOD(const AutofillProfile&, GetProfileToEdit, (), (const, override));
   MOCK_METHOD(void,
               OnUserDecision,
diff --git a/chrome/browser/ui/views/frame/DIR_METADATA b/chrome/browser/ui/views/frame/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/views/frame/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/ui/views/layout_provider_unittest.cc b/chrome/browser/ui/views/layout_provider_unittest.cc
index daa62f36..7e78a3c 100644
--- a/chrome/browser/ui/views/layout_provider_unittest.cc
+++ b/chrome/browser/ui/views/layout_provider_unittest.cc
@@ -53,6 +53,9 @@
     base::win::EnableHighDPISupport();
 #endif
     gfx::InitializeFonts();
+    // Some previous test may have left the default font description set to an
+    // unexpected state.
+    gfx::FontList::SetDefaultFontDescription(std::string());
   }
 
  private:
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 5c489b5..3ea3410 100644
--- a/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
+++ b/chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.cc
@@ -234,7 +234,8 @@
     PopulateAppDict(app_data, app_info.get());
     apps_list->Append(std::move(app_info));
   }
-  settings->SetWithoutPathExpansion("apps", std::move(apps_list));
+  settings->SetKey("apps",
+                   base::Value::FromUniquePtrValue(std::move(apps_list)));
 
   return settings;
 }
diff --git a/chrome/browser/ui/webui/new_tab_page/foo/DIR_METADATA b/chrome/browser/ui/webui/new_tab_page/foo/DIR_METADATA
deleted file mode 100644
index 77ca58f..0000000
--- a/chrome/browser/ui/webui/new_tab_page/foo/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>NewTabPage"
-}
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/DIR_METADATA b/chrome/browser/ui/webui/settings/chromeos/search/DIR_METADATA
deleted file mode 100644
index 2d34b2f4..0000000
--- a/chrome/browser/ui/webui/settings/chromeos/search/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "OS>Systems>Settings"
-}
diff --git a/chrome/browser/ui/webui/tab_strip/DIR_METADATA b/chrome/browser/ui/webui/tab_strip/DIR_METADATA
deleted file mode 100644
index 8325efa..0000000
--- a/chrome/browser/ui/webui/tab_strip/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>WebUI"
-}
diff --git a/chrome/browser/ui/webui/util/DIR_METADATA b/chrome/browser/ui/webui/util/DIR_METADATA
deleted file mode 100644
index 8325efa..0000000
--- a/chrome/browser/ui/webui/util/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>WebUI"
-}
diff --git a/chrome/browser/ui/window_sizer/DIR_METADATA b/chrome/browser/ui/window_sizer/DIR_METADATA
deleted file mode 100644
index 9719bd8..0000000
--- a/chrome/browser/ui/window_sizer/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser"
-}
diff --git a/chrome/browser/vr/vector_icons/DIR_METADATA b/chrome/browser/vr/vector_icons/DIR_METADATA
deleted file mode 100644
index f4b55f85..0000000
--- a/chrome/browser/vr/vector_icons/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "UI>Browser>VR"
-}
-team_email: "xr-dev@chromium.org"
diff --git a/chrome/browser/web_applications/chrome_pwa_launcher/DIR_METADATA b/chrome/browser/web_applications/chrome_pwa_launcher/DIR_METADATA
index f49f5ea..8f69a62 100644
--- a/chrome/browser/web_applications/chrome_pwa_launcher/DIR_METADATA
+++ b/chrome/browser/web_applications/chrome_pwa_launcher/DIR_METADATA
@@ -1,5 +1 @@
-monorail: {
-  component: "UI>Browser>WebAppInstalls"
-}
-team_email: "pwa-dev@chromium.org"
 os: WINDOWS
diff --git a/chrome/browser/web_applications/components/externally_managed_app_manager.h b/chrome/browser/web_applications/components/externally_managed_app_manager.h
index 1fdd54a..c6d19a9 100644
--- a/chrome/browser/web_applications/components/externally_managed_app_manager.h
+++ b/chrome/browser/web_applications/components/externally_managed_app_manager.h
@@ -91,6 +91,14 @@
   //
   // Fails if the same operation has been queued before. Should only be used in
   // response to a user action e.g. the user clicked an install button.
+  virtual void InstallNow(ExternalInstallOptions install_options,
+                          OnceInstallCallback callback) = 0;
+
+  // Queues an installation operation the end of current tasks. Runs its
+  // callback with the URL in |install_options| and with the id of the installed
+  // app or an empty string if the installation fails.
+  //
+  // Fails if the same operation has been queued before.
   virtual void Install(ExternalInstallOptions install_options,
                        OnceInstallCallback callback) = 0;
 
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl.cc b/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
index 57d6ec3..cdb9ca13 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager_impl.cc
@@ -43,7 +43,7 @@
 
 ExternallyManagedAppManagerImpl::~ExternallyManagedAppManagerImpl() = default;
 
-void ExternallyManagedAppManagerImpl::Install(
+void ExternallyManagedAppManagerImpl::InstallNow(
     ExternalInstallOptions install_options,
     OnceInstallCallback callback) {
   pending_installs_.push_front(std::make_unique<TaskAndCallback>(
@@ -52,6 +52,15 @@
   PostMaybeStartNext();
 }
 
+void ExternallyManagedAppManagerImpl::Install(
+    ExternalInstallOptions install_options,
+    OnceInstallCallback callback) {
+  pending_installs_.push_back(std::make_unique<TaskAndCallback>(
+      CreateInstallationTask(std::move(install_options)), std::move(callback)));
+
+  PostMaybeStartNext();
+}
+
 void ExternallyManagedAppManagerImpl::InstallApps(
     std::vector<ExternalInstallOptions> install_options_list,
     const RepeatingInstallCallback& callback) {
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl.h b/chrome/browser/web_applications/externally_managed_app_manager_impl.h
index 308e7927..a244578 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager_impl.h
+++ b/chrome/browser/web_applications/externally_managed_app_manager_impl.h
@@ -42,6 +42,8 @@
   ~ExternallyManagedAppManagerImpl() override;
 
   // ExternallyManagedAppManager:
+  void InstallNow(ExternalInstallOptions install_options,
+                  OnceInstallCallback callback) override;
   void Install(ExternalInstallOptions install_options,
                OnceInstallCallback callback) override;
   void InstallApps(std::vector<ExternalInstallOptions> install_options_list,
diff --git a/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc b/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
index 7df023b..426f62e8 100644
--- a/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
+++ b/chrome/browser/web_applications/externally_managed_app_manager_impl_unittest.cc
@@ -453,7 +453,7 @@
     absl::optional<GURL> url;
     absl::optional<InstallResultCode> code;
 
-    externally_managed_app_manager_impl()->Install(
+    externally_managed_app_manager_impl()->InstallNow(
         std::move(install_options),
         base::BindLambdaForTesting(
             [&](const GURL& u,
@@ -649,7 +649,7 @@
       FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
 
   base::RunLoop run_loop;
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -665,7 +665,7 @@
 
             run_loop.Quit();
           }));
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetBarInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -691,7 +691,7 @@
   base::RunLoop foo_run_loop;
   base::RunLoop bar_run_loop;
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -709,7 +709,7 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(install_task_manager().num_pending_tasks(), 1u);
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetBarInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -739,7 +739,7 @@
 
   base::RunLoop foo_run_loop;
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptionsWithWebAppInfo(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -833,7 +833,7 @@
   base::RunLoop foo_run_loop;
   base::RunLoop bar_run_loop;
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -849,7 +849,7 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_EQ(install_task_manager().num_pending_tasks(), 1u);
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetBarInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -897,13 +897,13 @@
         EXPECT_EQ(1u, install_run_count());
         EXPECT_EQ(GetFooInstallOptions(), last_install_options());
 
-        externally_managed_app_manager_impl()->Install(GetBarInstallOptions(),
-                                                       final_callback);
+        externally_managed_app_manager_impl()->InstallNow(
+            GetBarInstallOptions(), final_callback);
       });
 
   // Call Install() with a callback that tries to install another app.
-  externally_managed_app_manager_impl()->Install(GetFooInstallOptions(),
-                                                 reentrant_callback);
+  externally_managed_app_manager_impl()->InstallNow(GetFooInstallOptions(),
+                                                    reentrant_callback);
   run_loop.Run();
 }
 
@@ -944,7 +944,7 @@
   base::RunLoop run_loop;
   bool first_callback_ran = false;
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -963,7 +963,7 @@
             run_loop.Quit();
           }));
 
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -1226,7 +1226,7 @@
           }));
 
   // Queue through Install.
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetQuxInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -1260,7 +1260,7 @@
   base::RunLoop run_loop;
 
   // Queue through Install.
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetQuxInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
@@ -1452,7 +1452,7 @@
       FooWebAppUrl(), InstallResultCode::kSuccessNewInstall);
 
   base::RunLoop run_loop;
-  externally_managed_app_manager_impl()->Install(
+  externally_managed_app_manager_impl()->InstallNow(
       GetFooInstallOptions(),
       base::BindLambdaForTesting(
           [&](const GURL& url,
diff --git a/chrome/browser/web_applications/policy/web_app_policy_manager.cc b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
index e84b91a..09b14c9 100644
--- a/chrome/browser/web_applications/policy/web_app_policy_manager.cc
+++ b/chrome/browser/web_applications/policy/web_app_policy_manager.cc
@@ -147,8 +147,8 @@
 
   // If the app is not a placeholder app, ExternallyManagedAppManager will
   // ignore the request.
-  externally_managed_app_manager_->Install(std::move(install_options),
-                                           base::DoNothing());
+  externally_managed_app_manager_->InstallNow(std::move(install_options),
+                                              base::DoNothing());
 }
 
 // static
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc
index e64d1a46..1fe2393 100644
--- a/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc
+++ b/chrome/browser/web_applications/preinstalled_web_apps/google_chat.cc
@@ -15,7 +15,8 @@
       /*user_display_mode=*/DisplayMode::kStandalone,
       /*install_source=*/ExternalInstallSource::kExternalDefault);
 
-  options.user_type_allowlist = {"unmanaged", "managed", "child"};
+  // Exclude managed users until we have a way for admins to block the app.
+  options.user_type_allowlist = {"unmanaged", "child"};
   options.gate_on_feature = kDefaultChatWebApp.name;
   options.only_for_new_users = true;
   options.add_to_quick_launch_bar = false;
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/google_meet.cc b/chrome/browser/web_applications/preinstalled_web_apps/google_meet.cc
index d27f207..aaae134 100644
--- a/chrome/browser/web_applications/preinstalled_web_apps/google_meet.cc
+++ b/chrome/browser/web_applications/preinstalled_web_apps/google_meet.cc
@@ -15,7 +15,8 @@
       /*user_display_mode=*/DisplayMode::kStandalone,
       /*install_source=*/ExternalInstallSource::kExternalDefault);
 
-  options.user_type_allowlist = {"unmanaged", "managed", "child"};
+  // Exclude managed users until we have a way for admins to block the app.
+  options.user_type_allowlist = {"unmanaged", "child"};
   options.gate_on_feature = kDefaultMeetWebApp.name;
   options.only_for_new_users = true;
   options.add_to_quick_launch_bar = false;
diff --git a/chrome/browser/web_applications/test/test_externally_managed_app_manager.cc b/chrome/browser/web_applications/test/test_externally_managed_app_manager.cc
index 2cd1234..abc94f86 100644
--- a/chrome/browser/web_applications/test/test_externally_managed_app_manager.cc
+++ b/chrome/browser/web_applications/test/test_externally_managed_app_manager.cc
@@ -42,6 +42,12 @@
   install_result_code_ = result_code;
 }
 
+void TestExternallyManagedAppManager::InstallNow(
+    ExternalInstallOptions install_options,
+    OnceInstallCallback callback) {
+  Install(install_options, std::move(callback));
+}
+
 void TestExternallyManagedAppManager::Install(
     ExternalInstallOptions install_options,
     OnceInstallCallback callback) {
diff --git a/chrome/browser/web_applications/test/test_externally_managed_app_manager.h b/chrome/browser/web_applications/test/test_externally_managed_app_manager.h
index fec88f3..1543d0e 100644
--- a/chrome/browser/web_applications/test/test_externally_managed_app_manager.h
+++ b/chrome/browser/web_applications/test/test_externally_managed_app_manager.h
@@ -52,6 +52,8 @@
   void SetInstallResultCode(InstallResultCode result_code);
 
   // ExternallyManagedAppManager:
+  void InstallNow(ExternalInstallOptions install_options,
+                  OnceInstallCallback callback) override;
   void Install(ExternalInstallOptions install_options,
                OnceInstallCallback callback) override;
   void InstallApps(std::vector<ExternalInstallOptions> install_options_list,
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index cf99587..10fe3164 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1621284927-c6e8e7c33fcfe3d82df9246db011c64fc4b86c8c.profdata
+chrome-win32-master-1621295939-5e3a052a5ca44d71eb09eaecaed845e63fd6b5fb.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 186ef9d..d6c42a9 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1621284927-50282b38fb606fedaa249ec8ccc64b12c53af681.profdata
+chrome-win64-master-1621317594-47b478011c6406da2b339aae76448ec925fdf8a5.profdata
diff --git a/chrome/installer/gcapi_mac/DIR_METADATA b/chrome/installer/gcapi_mac/DIR_METADATA
deleted file mode 100644
index 0c97fbf..0000000
--- a/chrome/installer/gcapi_mac/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>Installer"
-}
diff --git a/chrome/installer/mac/DIR_METADATA b/chrome/installer/mac/DIR_METADATA
deleted file mode 100644
index 0c97fbf..0000000
--- a/chrome/installer/mac/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>Installer"
-}
diff --git a/chrome/services/file_util/zip_file_creator.cc b/chrome/services/file_util/zip_file_creator.cc
index 2b1bcba6..cceac858 100644
--- a/chrome/services/file_util/zip_file_creator.cc
+++ b/chrome/services/file_util/zip_file_creator.cc
@@ -99,20 +99,21 @@
     base::File::Error error;
     dir->Read(&error, &directory_contents);
     if (error != base::File::Error::FILE_OK) {
-      LOG(ERROR) << "Failed to list content of " << dir_path.value()
-                 << " error " << error;
+      LOG(ERROR) << "Cannot list content of '" << dir_path << "': Error "
+                 << error;
       return results;
     }
+
     if (directory_contents) {
       results.reserve(directory_contents->size());
       for (const filesystem::mojom::DirectoryEntryPtr& entry :
            *directory_contents) {
-        base::FilePath path = dir_path.Append(entry->name);
-        bool is_directory =
-            entry->type == filesystem::mojom::FsFileType::DIRECTORY;
-        results.push_back(DirectoryContentEntry(path, is_directory));
+        results.push_back(
+            {dir_path.Append(entry->name),
+             entry->type == filesystem::mojom::FsFileType::DIRECTORY});
       }
     }
+
     return results;
   }
 
diff --git a/chrome/services/sharing/nearby/DIR_METADATA b/chrome/services/sharing/nearby/DIR_METADATA
deleted file mode 100644
index 135a13c..0000000
--- a/chrome/services/sharing/nearby/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI>Browser>Sharing>Nearby"
-}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 491f0a7d..a1d7cd3 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1871,7 +1871,6 @@
         "//ui/file_manager/audio_player/js:modulize_runtime_data",
         "//ui/file_manager/file_manager/background/js:modulize_runtime_data",
         "//ui/file_manager/file_manager/common/js:modulize_runtime_data",
-        "//ui/file_manager/file_manager/cws_widget:modulize_runtime_data",
         "//ui/file_manager/file_manager/externs:modulize_runtime_data",
         "//ui/file_manager/file_manager/externs/background:modulize_runtime_data",
         "//ui/file_manager/file_manager/foreground/elements:modulize_runtime_data",
diff --git a/chrome/test/android/test_trusted_web_activity/DIR_METADATA b/chrome/test/android/test_trusted_web_activity/DIR_METADATA
index e83fdb9..37dd89f3 100644
--- a/chrome/test/android/test_trusted_web_activity/DIR_METADATA
+++ b/chrome/test/android/test_trusted_web_activity/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Mobile>TrustedWebActivities"
 }
-os: ANDROID
diff --git a/chrome/test/chromedriver/chrome/log.cc b/chrome/test/chromedriver/chrome/log.cc
index 6a750cfa..1bb71d00 100644
--- a/chrome/test/chromedriver/chrome/log.cc
+++ b/chrome/test/chromedriver/chrome/log.cc
@@ -54,7 +54,8 @@
       }
       const base::Value* child = NULL;
       dict->GetWithoutPathExpansion(it.key(), &child);
-      dict_copy->SetWithoutPathExpansion(it.key(), SmartDeepCopy(child));
+      dict_copy->SetKey(it.key(),
+                        base::Value::FromUniquePtrValue(SmartDeepCopy(child)));
     }
     return std::move(dict_copy);
   } else if (value->GetAsList(&list)) {
diff --git a/chrome/test/enterprise/e2e/DIR_METADATA b/chrome/test/enterprise/e2e/DIR_METADATA
deleted file mode 100644
index 3ecb477..0000000
--- a/chrome/test/enterprise/e2e/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Enterprise"
-}
diff --git a/chromecast/android/DIR_METADATA b/chromecast/android/DIR_METADATA
deleted file mode 100644
index b339e61..0000000
--- a/chromecast/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Chromecast"
-}
diff --git a/chromecast/app/android/DIR_METADATA b/chromecast/app/android/DIR_METADATA
deleted file mode 100644
index b339e61..0000000
--- a/chromecast/app/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Chromecast"
-}
diff --git a/chromecast/base/android/DIR_METADATA b/chromecast/base/android/DIR_METADATA
deleted file mode 100644
index b339e61..0000000
--- a/chromecast/base/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Chromecast"
-}
diff --git a/chromecast/base/java/DIR_METADATA b/chromecast/base/java/DIR_METADATA
deleted file mode 100644
index b339e61..0000000
--- a/chromecast/base/java/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Chromecast"
-}
diff --git a/chromecast/browser/android/DIR_METADATA b/chromecast/browser/android/DIR_METADATA
deleted file mode 100644
index b339e61..0000000
--- a/chromecast/browser/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Chromecast"
-}
diff --git a/chromeos/chromeos_strings_grd/DIR_METADATA b/chromeos/chromeos_strings_grd/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/chromeos_strings_grd/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/components/DIR_METADATA b/chromeos/components/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/components/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/components/camera_app_ui/resources/css/main.css b/chromeos/components/camera_app_ui/resources/css/main.css
index ea00afd..51851e1 100644
--- a/chromeos/components/camera_app_ui/resources/css/main.css
+++ b/chromeos/components/camera_app_ui/resources/css/main.css
@@ -635,7 +635,7 @@
   margin: var(--option-item-vpadding) 0;
 }
 
-body:not(.has-ptz-support) #open-ptz-panel {
+body:not(.enable-ptz) #open-ptz-panel {
   display: none;
 }
 
diff --git a/chromeos/components/camera_app_ui/resources/js/device/camera3_device_info.js b/chromeos/components/camera_app_ui/resources/js/device/camera3_device_info.js
index 4fcda5f..3a8f0587 100644
--- a/chromeos/components/camera_app_ui/resources/js/device/camera3_device_info.js
+++ b/chromeos/components/camera_app_ui/resources/js/device/camera3_device_info.js
@@ -24,8 +24,10 @@
    * @param {!Array<!VideoConfig>} videoResolFpses Supported available video
    *     resolutions and maximal capture fps of the video device.
    * @param {!FpsRangeList} fpsRanges Supported fps ranges of the video device.
+   * @param {boolean} supportPTZ Is supported PTZ controls.
    */
-  constructor(deviceInfo, facing, photoResols, videoResolFpses, fpsRanges) {
+  constructor(
+      deviceInfo, facing, photoResols, videoResolFpses, fpsRanges, supportPTZ) {
     /**
      * @const {string}
      * @public
@@ -62,6 +64,12 @@
      */
     this.fpsRanges = fpsRanges;
 
+    /**
+     * @const {boolean}
+     * @public
+     */
+    this.supportPTZ = supportPTZ;
+
     videoResolFpses.filter(({maxFps}) => maxFps >= 24)
         .forEach(({width, height, maxFps}) => {
           const r = new Resolution(width, height);
@@ -87,6 +95,10 @@
       throw new Error('Device operation is not supported');
     }
     const facing = await deviceOperator.getCameraFacing(deviceId);
+    const supportPTZ =
+        (await deviceOperator.getPanDefault(deviceId)) !== undefined ||
+        (await deviceOperator.getTiltDefault(deviceId)) !== undefined ||
+        (await deviceOperator.getZoomDefault(deviceId)) !== undefined;
     const photoResolution = await deviceOperator.getPhotoResolutions(deviceId);
     const videoConfigs = await deviceOperator.getVideoConfigs(deviceId);
     const filteredVideoConfigs = videoConfigs.filter(videoConfigFilter);
@@ -95,6 +107,6 @@
 
     return new Camera3DeviceInfo(
         deviceInfo, facing, photoResolution, filteredVideoConfigs,
-        supportedFpsRanges);
+        supportedFpsRanges, supportPTZ);
   }
 }
diff --git a/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js b/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
index 3d5c7cb..f4a4242 100644
--- a/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
+++ b/chromeos/components/camera_app_ui/resources/js/device/constraints_preferrer.js
@@ -590,6 +590,12 @@
      */
     this.deviceCapturePreviewResolutionMap_ = new Map();
 
+    /**
+     * Maps from device id as key to whether PTZ is support from device level.
+     * @type {!Map<string, boolean>}
+     */
+    this.devicePTZSupportMap_ = new Map();
+
     this.restoreResolutionPreference_('devicePhotoResolution');
   }
 
@@ -612,6 +618,8 @@
   updateDevicesInfo(devices) {
     this.deviceCapturePreviewResolutionMap_ = new Map();
     this.supportedResolutions_ = new Map();
+    this.devicePTZSupportMap_ = new Map(
+        devices.map(({deviceId, supportPTZ}) => [deviceId, supportPTZ]));
 
     devices.forEach(({deviceId, photoResols, videoResols: previewResols}) => {
       const previewRatios = this.groupResolutionRatio_(previewResols);
@@ -665,6 +673,7 @@
   getSortedCandidates(deviceId) {
     /** @type {!Resolution} */
     const prefR = this.getPrefResolution(deviceId) || new Resolution(0, -1);
+    const supportPTZ = this.devicePTZSupportMap_.get(deviceId) || false;
 
     /**
      * @param {{captureRs: !ResolutionList, previewRs: !ResolutionList}} capture
@@ -677,6 +686,13 @@
             (captureR, r) => (r.width > captureR.width ? r : captureR));
       }
 
+      // Use workaround for b/184089334 on PTZ camera to use preview frame as
+      // photo result.
+      if (supportPTZ &&
+          previewRs.find((r) => captureR.equals(r)) !== undefined) {
+        previewRs = [captureR];
+      }
+
       const /** !Array<!MediaStreamConstraints> */ previewCandidates =
           this.sortPreview_(previewRs, captureR).map(({width, height}) => ({
                                                        audio: false,
diff --git a/chromeos/components/camera_app_ui/resources/js/state.js b/chromeos/components/camera_app_ui/resources/js/state.js
index 0637f25e6..9fe0565 100644
--- a/chromeos/components/camera_app_ui/resources/js/state.js
+++ b/chromeos/components/camera_app_ui/resources/js/state.js
@@ -17,6 +17,7 @@
   CAMERA_CONFIGURING: 'camera-configuring',
   CAMERA_SWITCHING: 'camera-switching',
   CUSTOM_VIDEO_PARAMETERS: 'custom-video-parameters',
+  ENABLE_PTZ: 'enable-ptz',
   EXPERT: 'expert',
   FPS_30: 'fps-30',
   FPS_60: 'fps-60',
@@ -27,7 +28,6 @@
   HAS_BACK_CAMERA: 'has-back-camera',
   HAS_EXTERNAL_SCREEN: 'has-external-screen',
   HAS_FRONT_CAMERA: 'has-front-camera',
-  HAS_PTZ_SUPPORT: 'has-ptz-support',
   HAS_PAN_SUPPORT: 'has-pan-support',
   HAS_TILT_SUPPORT: 'has-tilt-support',
   HAS_ZOOM_SUPPORT: 'has-zoom-support',
diff --git a/chromeos/components/camera_app_ui/resources/js/tooltip.js b/chromeos/components/camera_app_ui/resources/js/tooltip.js
index 03b4295..10ccc7b 100644
--- a/chromeos/components/camera_app_ui/resources/js/tooltip.js
+++ b/chromeos/components/camera_app_ui/resources/js/tooltip.js
@@ -17,11 +17,17 @@
 let hovered = null;
 
 /**
- * Positions the tooltip wrapper over the hovered element.
+ * Name of event triggered for positioning tooltip.
+ * @const {string}
  */
-function position() {
+export const TOOLTIP_POSITION_EVENT_NAME = 'tooltipposition';
+
+/**
+ * Positions tooltip relative to UI.
+ * @param {!DOMRectReadOnly} rect UI's reference region.
+ */
+export function position(rect) {
   const [edgeMargin, elementMargin] = [5, 8];
-  const rect = hovered.getBoundingClientRect();
   let tooltipTop = rect.top - wrapper.offsetHeight - elementMargin;
   if (tooltipTop < edgeMargin) {
     tooltipTop = rect.bottom + elementMargin;
@@ -29,7 +35,7 @@
   wrapper.style.top = tooltipTop + 'px';
 
   // Center over the hovered element but avoid touching edges.
-  const hoveredCenter = rect.left + hovered.offsetWidth / 2;
+  const hoveredCenter = rect.left + rect.width / 2;
   const left = Math.min(
       Math.max(hoveredCenter - wrapper.clientWidth / 2, edgeMargin),
       document.body.offsetWidth - wrapper.offsetWidth - edgeMargin);
@@ -64,7 +70,12 @@
   }
   wrapper.textContent = message;
   hovered = element;
-  position();
+  const positionEvent = new CustomEvent(
+      TOOLTIP_POSITION_EVENT_NAME, {cancelable: true, target: hovered});
+  const doDefault = hovered.dispatchEvent(positionEvent);
+  if (doDefault) {
+    position(hovered.getBoundingClientRect());
+  }
   wrapper.classList.add('visible');
 }
 
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera.js b/chromeos/components/camera_app_ui/resources/js/views/camera.js
index 2dd9a0f..929672e 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera.js
@@ -384,7 +384,7 @@
     };
 
     this.addConfigureCompleteListener_(async () => {
-      if (!state.get(state.State.HAS_PTZ_SUPPORT)) {
+      if (!state.get(state.State.ENABLE_PTZ)) {
         highlight(false);
         return;
       }
@@ -707,6 +707,28 @@
           }
           const stream = await this.preview_.open(constraints);
           this.facingMode_ = this.preview_.getFacing();
+
+          const enablePTZ = (() => {
+            if (!this.preview_.isSupportPTZ()) {
+              return false;
+            }
+            if (deviceOperator === null) {
+              // All fake VCD support PTZ controls.
+              return true;
+            }
+            if (this.facingMode_ !== Facing.EXTERNAL) {
+              // PTZ function is excluded from builtin camera until we set up
+              // its AVL calibration standard.
+              return false;
+            }
+            return this.modes_.isSupportPTZ(
+                mode,
+                captureR,
+                this.preview_.getResolution(),
+            );
+          })();
+          state.set(state.State.ENABLE_PTZ, enablePTZ);
+
           this.options_.updateValues(stream, this.facingMode_);
           factory.setPreviewStream(stream);
           factory.setFacing(this.facingMode_);
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
index e1834459..918e714 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/index.js
@@ -64,6 +64,14 @@
   async isSupported(deviceId) {}
 
   /**
+   * @param {!Resolution} captureResolution
+   * @param {!Resolution} previewResolution
+   * @return {boolean}
+   * @abstract
+   */
+  isSupportPTZ(captureResolution, previewResolution) {}
+
+  /**
    * Get general stream constraints of this mode for fake cameras.
    * @param {?string} deviceId
    * @return {!Array<!MediaStreamConstraints>}
@@ -164,6 +172,12 @@
       });
     };
 
+    // Workaround for b/184089334 on PTZ camera to use preview frame as photo
+    // result.
+    const checkSupportPTZForPhotoMode =
+        (captureResolution, previewResolution) =>
+            captureResolution.equals(previewResolution);
+
     /**
      * Mode classname and related functions and attributes.
      * @type {!Object<!Mode, !ModeConfig>}
@@ -173,6 +187,7 @@
       [Mode.VIDEO]: {
         captureFactory: new VideoFactory(videoHandler),
         isSupported: async () => true,
+        isSupportPTZ: () => true,
         constraintsPreferrer: videoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, true),
@@ -181,6 +196,7 @@
       [Mode.PHOTO]: {
         captureFactory: new PhotoFactory(photoHandler),
         isSupported: async () => true,
+        isSupportPTZ: checkSupportPTZForPhotoMode,
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
@@ -189,6 +205,7 @@
       [Mode.SQUARE]: {
         captureFactory: new SquareFactory(photoHandler),
         isSupported: async () => true,
+        isSupportPTZ: checkSupportPTZForPhotoMode,
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
@@ -206,6 +223,7 @@
           }
           return await deviceOperator.isPortraitModeSupported(deviceId);
         },
+        isSupportPTZ: checkSupportPTZForPhotoMode,
         constraintsPreferrer: photoPreferrer,
         getConstraintsForFakeCamera:
             getConstraintsForFakeCamera.bind(this, false),
@@ -341,6 +359,17 @@
   }
 
   /**
+   * @param {!Mode} mode
+   * @param {!Resolution} captureResolution
+   * @param {!Resolution} previewResolution
+   * @return {boolean}
+   */
+  isSupportPTZ(mode, captureResolution, previewResolution) {
+    return this.allModes_[mode].isSupportPTZ(
+        captureResolution, previewResolution);
+  }
+
+  /**
    * Updates mode selection UI according to given device id.
    * @param {?string} deviceId
    * @return {!Promise}
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
index ad44443..32c227e 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/photo.js
@@ -47,6 +47,13 @@
    * Plays UI effect when taking photo.
    */
   playShutterEffect() {}
+
+  /**
+   * Gets frame image blob from current preview.
+   * @return {!Promise<!Blob>}
+   * @abstract
+   */
+  getPreviewFrame() {}
 }
 
 /**
@@ -91,6 +98,15 @@
   }
 
   /**
+   * @return {boolean}
+   */
+  supportPTZ_() {
+    const {pan, tilt, zoom} =
+        this.stream_.getVideoTracks()[0].getCapabilities();
+    return pan !== undefined || tilt !== undefined || zoom !== undefined;
+  }
+
+  /**
    * @override
    */
   async start_() {
@@ -99,43 +115,19 @@
           new CrosImageCapture(this.stream_.getVideoTracks()[0]);
     }
 
-    await this.takePhoto_();
-  }
-
-  /**
-   * Takes and saves a photo.
-   * @return {!Promise}
-   * @private
-   */
-  async takePhoto_() {
     const imageName = (new Filenamer()).newImageName();
     if (this.metadataObserverId_ !== null) {
       this.metadataNames_.push(Filenamer.getMetadataName(imageName));
     }
 
-    let photoSettings;
-    if (this.captureResolution_) {
-      photoSettings = /** @type {!PhotoSettings} */ ({
-        imageWidth: this.captureResolution_.width,
-        imageHeight: this.captureResolution_.height,
-      });
-    } else {
-      const caps = await this.crosImageCapture_.getPhotoCapabilities();
-      photoSettings = /** @type {!PhotoSettings} */ ({
-        imageWidth: caps.imageWidth.max,
-        imageHeight: caps.imageHeight.max,
-      });
-    }
 
     state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, true);
     try {
-      const results = await this.crosImageCapture_.takePhoto(photoSettings);
-
       state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {facing: this.facing_});
       this.handler_.playShutterEffect();
 
       state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true);
-      const blob = await results[0];
+      const blob = await this.takePhoto_();
       const image = await util.blobToImage(blob);
       const resolution = new Resolution(image.width, image.height);
       await this.handler_.handleResultPhoto({resolution, blob}, imageName);
@@ -152,6 +144,32 @@
   }
 
   /**
+   * @return {!Promise<!Blob>}
+   */
+  async takePhoto_() {
+    if (this.supportPTZ_()) {
+      // Workaround for b/184089334 on PTZ camera to use preview frame as
+      // photo result.
+      return this.handler_.getPreviewFrame();
+    }
+    let photoSettings;
+    if (this.captureResolution_) {
+      photoSettings = /** @type {!PhotoSettings} */ ({
+        imageWidth: this.captureResolution_.width,
+        imageHeight: this.captureResolution_.height,
+      });
+    } else {
+      const caps = await this.crosImageCapture_.getPhotoCapabilities();
+      photoSettings = /** @type {!PhotoSettings} */ ({
+        imageWidth: caps.imageWidth.max,
+        imageHeight: caps.imageHeight.max,
+      });
+    }
+    const results = await this.crosImageCapture_.takePhoto(photoSettings);
+    return results[0];
+  }
+
+  /**
    * Adds an observer to save metadata.
    * @return {!Promise} Promise for the operation.
    */
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/square.js b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/square.js
index 9e09f7b..8664c047 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/mode/square.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/mode/square.js
@@ -67,6 +67,13 @@
   playShutterEffect() {
     this.handler_.playShutterEffect();
   }
+
+  /**
+   * @override
+   */
+  getPreviewFrame() {
+    return this.handler_.getPreviewFrame();
+  }
 }
 
 /**
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
index e2a8523d..7e66817b 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -10,7 +10,7 @@
 import {DeviceOperator, parseMetadata} from '../../mojo/device_operator.js';
 import * as nav from '../../nav.js';
 import * as state from '../../state.js';
-import {Facing, Mode} from '../../type.js';
+import {Facing, Mode, Resolution} from '../../type.js';
 import * as util from '../../util.js';
 import {windowController} from '../../window_controller.js';
 
@@ -151,6 +151,24 @@
   }
 
   /**
+   * If the preview camera support PTZ controls.
+   * @return {boolean}
+   */
+  isSupportPTZ() {
+    const {pan, tilt, zoom} = this.getVideoTrack_().getCapabilities();
+    return pan !== undefined || tilt !== undefined || zoom !== undefined;
+  }
+
+  /**
+   * Preview resolution.
+   * @return {!Resolution}
+   */
+  getResolution() {
+    const {videoWidth, videoHeight} = this.video_;
+    return new Resolution(videoWidth, videoHeight);
+  }
+
+  /**
    * @override
    */
   toString() {
@@ -227,14 +245,6 @@
         }
       }
 
-      const {pan, tilt, zoom} = this.getVideoTrack_().getCapabilities();
-      // PTZ function is excluded from builtin camera until we set up its AVL
-      // calibration standard.
-      state.set(
-          state.State.HAS_PTZ_SUPPORT,
-          (this.facing_ === Facing.NOT_SET ||
-           this.facing_ === Facing.EXTERNAL) &&
-              (pan !== undefined || tilt !== undefined || zoom !== undefined));
       state.set(state.State.STREAMING, true);
     } catch (e) {
       await this.close();
diff --git a/chromeos/components/camera_app_ui/resources/js/views/ptz_panel.js b/chromeos/components/camera_app_ui/resources/js/views/ptz_panel.js
index 66bd7916..472a059 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/ptz_panel.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/ptz_panel.js
@@ -3,12 +3,14 @@
 // found in the LICENSE file.
 
 import {AsyncJobQueue} from '../async_job_queue.js';
+import {assertInstanceof} from '../chrome_util.js';
 import * as dom from '../dom.js';
 import * as focusRing from '../focus_ring.js';
 import * as metrics from '../metrics.js';
 import {DeviceOperator} from '../mojo/device_operator.js';
 import * as nav from '../nav.js';
 import * as state from '../state.js';
+import * as tooltip from '../tooltip.js';
 import {ViewName} from '../type.js';
 
 // eslint-disable-next-line no-unused-vars
@@ -211,6 +213,26 @@
         nav.close(this.name);
       }
     });
+    [this.panRight_, this.panLeft_, this.tiltUp_, this.tiltDown_].forEach(
+        (btn) => {
+          btn.addEventListener(tooltip.TOOLTIP_POSITION_EVENT_NAME, (e) => {
+            const target = assertInstanceof(e.target, HTMLElement);
+            const pRect = target.offsetParent.getBoundingClientRect();
+            const style = getComputedStyle(target, '::before');
+            const getStyleValue = (attr) => {
+              const px = style.getPropertyValue(attr);
+              return Number(px.replace(/^([\d.]+)px$/, '$1'));
+            };
+            const offsetX = getStyleValue('left');
+            const offsetY = getStyleValue('top');
+            const width = getStyleValue('width');
+            const height = getStyleValue('height');
+            tooltip.position(new DOMRectReadOnly(
+                /* x */ pRect.left + offsetX, /* y */ pRect.top + offsetY,
+                width, height));
+            e.preventDefault();
+          });
+        });
   }
 
   /**
diff --git a/chromeos/components/file_manager/mojom/DIR_METADATA b/chromeos/components/file_manager/mojom/DIR_METADATA
deleted file mode 100644
index 5b8d7cd..0000000
--- a/chromeos/components/file_manager/mojom/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Apps>FileManager"
-}
diff --git a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
index c6b15d2..7680bf35 100644
--- a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
+++ b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager.cc
@@ -154,8 +154,9 @@
   new_current_user_prefs->SetKey(
       prefs::kProximityAuthHasShownLoginDisabledMessage,
       base::Value(has_shown));
-  update->SetWithoutPathExpansion(active_user_.GetUserEmail(),
-                                  std::move(new_current_user_prefs));
+  update->SetKey(
+      active_user_.GetUserEmail(),
+      base::Value::FromUniquePtrValue(std::move(new_current_user_prefs)));
 }
 
 bool ProximityAuthLocalStatePrefManager::HasShownLoginDisabledMessage() const {
diff --git a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
index ac90c23..f573745 100644
--- a/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
+++ b/chromeos/components/proximity_auth/proximity_auth_local_state_pref_manager_unittest.cc
@@ -62,8 +62,8 @@
                         base::Value(kIsEasyUnlockEnabled1));
     DictionaryPrefUpdate update1(&local_state_,
                                  prefs::kEasyUnlockLocalStateUserPrefs);
-    update1->SetWithoutPathExpansion(user1_.GetUserEmail(),
-                                     std::move(user1_prefs));
+    update1->SetKey(user1_.GetUserEmail(),
+                    base::Value::FromUniquePtrValue(std::move(user1_prefs)));
 
     std::unique_ptr<base::DictionaryValue> user2_prefs(
         new base::DictionaryValue());
@@ -77,8 +77,8 @@
 
     DictionaryPrefUpdate update2(&local_state_,
                                  prefs::kEasyUnlockLocalStateUserPrefs);
-    update2->SetWithoutPathExpansion(user2_.GetUserEmail(),
-                                     std::move(user2_prefs));
+    update2->SetKey(user2_.GetUserEmail(),
+                    base::Value::FromUniquePtrValue(std::move(user2_prefs)));
   }
 
   AccountId user1_;
diff --git a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc
index 4a0c9adc..fa9fede 100644
--- a/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc
+++ b/chromeos/components/proximity_auth/proximity_auth_profile_pref_manager.cc
@@ -105,8 +105,8 @@
 
   DictionaryPrefUpdate update(local_state_,
                               prefs::kEasyUnlockLocalStateUserPrefs);
-  update->SetWithoutPathExpansion(account_id_.GetUserEmail(),
-                                  std::move(user_prefs_dict));
+  update->SetKey(account_id_.GetUserEmail(),
+                 base::Value::FromUniquePtrValue(std::move(user_prefs_dict)));
 }
 
 bool ProximityAuthProfilePrefManager::IsEasyUnlockAllowed() const {
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index bd2cefaa..02889533 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -50,6 +50,8 @@
     "//printing/mojom",
     "//services/device/public/mojom:mojom",
     "//services/media_session/public/mojom:mojom",
+    "//ui/accessibility:ax_enums_mojo",
+    "//ui/accessibility/mojom",
     "//ui/base/mojom",
     "//ui/gfx/geometry/mojom",
     "//ui/gfx/image/mojom",
@@ -70,6 +72,11 @@
           mojom = "crosapi.mojom.UninstallSource"
           cpp = "::apps::mojom::UninstallSource"
         },
+        {
+          mojom = "crosapi.mojom.CapabilityAccess"
+          cpp = "::apps::mojom::CapabilityAccessPtr"
+          move_only = true
+        },
       ]
       traits_headers = [
         "//chromeos/crosapi/mojom/app_service_types_mojom_traits.h",
diff --git a/chromeos/crosapi/mojom/app_service.mojom b/chromeos/crosapi/mojom/app_service.mojom
index 5f1c3d9..3048f4b 100644
--- a/chromeos/crosapi/mojom/app_service.mojom
+++ b/chromeos/crosapi/mojom/app_service.mojom
@@ -18,6 +18,11 @@
   // launch, or otherwise interact with Web Apps that run in Lacros.
   [MinVersion=1]
   RegisterAppController@1(pending_remote<AppController> controller);
+
+  // Receives a stream of accesses from lacros-chrome, and saves to
+  // AppCapabilityAccess.
+  [MinVersion=2]
+  OnCapabilityAccesses@2(array<CapabilityAccess> deltas);
 };
 
 // Interacts with the app service. Implemented in lacros-chrome and called in
diff --git a/chromeos/crosapi/mojom/app_service_types.mojom b/chromeos/crosapi/mojom/app_service_types.mojom
index 311ec54..746be3b 100644
--- a/chromeos/crosapi/mojom/app_service_types.mojom
+++ b/chromeos/crosapi/mojom/app_service_types.mojom
@@ -197,3 +197,16 @@
   kShelf,         // Uninstall by the user from the Shelf
   kMigration,     // Uninstall by app migration.
 };
+
+// Information about whether an app is accessing some capability, e.g. camera,
+// microphone.
+[Stable]
+struct CapabilityAccess {
+  string app_id;
+
+  // Whether the app is accessing camera.
+  OptionalBool camera;
+
+  // Whether the app is accessing microphone.
+  OptionalBool microphone;
+};
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
index e096b57..97366fe5 100644
--- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
+++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.cc
@@ -526,4 +526,28 @@
   return false;
 }
 
+bool StructTraits<crosapi::mojom::CapabilityAccessDataView,
+                  apps::mojom::CapabilityAccessPtr>::
+    Read(crosapi::mojom::CapabilityAccessDataView data,
+         apps::mojom::CapabilityAccessPtr* out) {
+  std::string app_id;
+  if (!data.ReadAppId(&app_id))
+    return false;
+
+  apps::mojom::OptionalBool camera;
+  if (!data.ReadCamera(&camera))
+    return false;
+
+  apps::mojom::OptionalBool microphone;
+  if (!data.ReadMicrophone(&microphone))
+    return false;
+
+  auto capability_access = apps::mojom::CapabilityAccess::New();
+  capability_access->app_id = std::move(app_id);
+  capability_access->camera = std::move(camera);
+  capability_access->microphone = std::move(microphone);
+  *out = std::move(capability_access);
+  return true;
+}
+
 }  // namespace mojo
diff --git a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
index 00bbb267..45472fc 100644
--- a/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
+++ b/chromeos/crosapi/mojom/app_service_types_mojom_traits.h
@@ -249,6 +249,27 @@
                         apps::mojom::UninstallSource* output);
 };
 
+template <>
+struct StructTraits<crosapi::mojom::CapabilityAccessDataView,
+                    apps::mojom::CapabilityAccessPtr> {
+  static const std::string& app_id(const apps::mojom::CapabilityAccessPtr& r) {
+    return r->app_id;
+  }
+
+  static const apps::mojom::OptionalBool& camera(
+      const apps::mojom::CapabilityAccessPtr& r) {
+    return r->camera;
+  }
+
+  static const apps::mojom::OptionalBool& microphone(
+      const apps::mojom::CapabilityAccessPtr& r) {
+    return r->microphone;
+  }
+
+  static bool Read(crosapi::mojom::CapabilityAccessDataView,
+                   apps::mojom::CapabilityAccessPtr* out);
+};
+
 }  // namespace mojo
 
 #endif  // CHROMEOS_CROSAPI_MOJOM_APP_SERVICE_TYPES_MOJOM_TRAITS_H_
diff --git a/chromeos/crosapi/mojom/automation.mojom b/chromeos/crosapi/mojom/automation.mojom
index 41afd4d14..d8eca6b 100644
--- a/chromeos/crosapi/mojom/automation.mojom
+++ b/chromeos/crosapi/mojom/automation.mojom
@@ -6,6 +6,7 @@
 
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "mojo/public/mojom/base/values.mojom";
+import "ui/accessibility/mojom/ax_action_data.mojom";
 
 // Interface for automation clients. Implemented by lacros-chrome. Used by
 // ash-chrome to enable automation and to perform actions.
@@ -38,8 +39,8 @@
 };
 
 // Interface for automation. Implemented by ash-chrome.
-// Next version: 2
-// Next method id: 3
+// Next version: 3
+// Next method id: 4
 [Stable, Uuid="356a895e-b41a-4c45-9336-d8dc6d332f98"]
 interface Automation {
   // Deprecated.
@@ -65,6 +66,9 @@
   // in Lacros to Ash.
   [MinVersion=1]DispatchTreeDestroyedEvent@2(
       mojo_base.mojom.UnguessableToken tree_id);
+
+  // Forwards an action result from any accessibility tree in Lacros to Ash.
+  [MinVersion=2]DispatchActionResult@3(ax.mojom.AXActionData data, bool result);
 };
 
 // A factory living in the Ash process which brokers connections to other
diff --git a/chromeos/geolocation/simple_geolocation_request.cc b/chromeos/geolocation/simple_geolocation_request.cc
index 0292549..5d31abc 100644
--- a/chromeos/geolocation/simple_geolocation_request.cc
+++ b/chromeos/geolocation/simple_geolocation_request.cc
@@ -396,8 +396,8 @@
     for (const WifiAccessPoint& access_point : *wifi_data_) {
       wifi_access_points->Append(CreateAccessPointDictionary(access_point));
     }
-    request->SetWithoutPathExpansion(kWifiAccessPoints,
-                                     std::move(wifi_access_points));
+    request->SetKey(kWifiAccessPoints, base::Value::FromUniquePtrValue(
+                                           std::move(wifi_access_points)));
   }
 
   if (cell_tower_data_) {
@@ -405,7 +405,8 @@
     for (const CellTower& cell_tower : *cell_tower_data_) {
       cell_towers->Append(CreateCellTowerDictionary(cell_tower));
     }
-    request->SetWithoutPathExpansion(kCellTowers, std::move(cell_towers));
+    request->SetKey(kCellTowers,
+                    base::Value::FromUniquePtrValue(std::move(cell_towers)));
   }
 
   std::string result;
diff --git a/chromeos/network/network_state_unittest.cc b/chromeos/network/network_state_unittest.cc
index e0c1edf4..3f2f81c6 100644
--- a/chromeos/network/network_state_unittest.cc
+++ b/chromeos/network/network_state_unittest.cc
@@ -28,7 +28,7 @@
  protected:
   bool SetProperty(const std::string& key, std::unique_ptr<base::Value> value) {
     const bool result = network_state_.PropertyChanged(key, *value);
-    properties_.SetWithoutPathExpansion(key, std::move(value));
+    properties_.SetKey(key, base::Value::FromUniquePtrValue(std::move(value)));
     return result;
   }
 
diff --git a/chromeos/network/onc/onc_mapper.cc b/chromeos/network/onc/onc_mapper.cc
index 804586c..b583752 100644
--- a/chromeos/network/onc/onc_mapper.cc
+++ b/chromeos/network/onc/onc_mapper.cc
@@ -80,7 +80,8 @@
     if (current_field_unknown)
       *found_unknown_field = true;
     else if (result_value.get() != NULL)
-      result->SetWithoutPathExpansion(it.first, std::move(result_value));
+      result->SetKey(it.first,
+                     base::Value::FromUniquePtrValue(std::move(result_value)));
     else
       DCHECK(*nested_error);
   }
diff --git a/chromeos/network/onc/onc_merger.cc b/chromeos/network/onc/onc_merger.cc
index 021dc5d6..8e334213 100644
--- a/chromeos/network/onc/onc_merger.cc
+++ b/chromeos/network/onc/onc_merger.cc
@@ -76,8 +76,8 @@
       continue;
     }
 
-    result_editable->SetWithoutPathExpansion(it.key(),
-                                             GetEditableFlags(*child_policy));
+    result_editable->SetKey(it.key(), base::Value::FromUniquePtrValue(
+                                          GetEditableFlags(*child_policy)));
   }
   return result_editable;
 }
@@ -137,7 +137,8 @@
         }
 
         if (merged_value)
-          result->SetWithoutPathExpansion(key, std::move(merged_value));
+          result->SetKey(
+              key, base::Value::FromUniquePtrValue(std::move(merged_value)));
       }
     }
     return result;
diff --git a/chromeos/network/onc/onc_utils.cc b/chromeos/network/onc/onc_utils.cc
index 691afc4be..95f5e5e 100644
--- a/chromeos/network/onc/onc_utils.cc
+++ b/chromeos/network/onc/onc_utils.cc
@@ -285,7 +285,8 @@
   }
 
   onc_object->RemoveKey(key_guid_ref_list);
-  onc_object->SetWithoutPathExpansion(key_pem_list, std::move(pem_list));
+  onc_object->SetKey(key_pem_list,
+                     base::Value::FromUniquePtrValue(std::move(pem_list)));
   return true;
 }
 
@@ -306,7 +307,8 @@
   std::unique_ptr<base::ListValue> pem_list(new base::ListValue);
   pem_list->AppendString(pem_encoded);
   onc_object->RemoveKey(key_guid_ref);
-  onc_object->SetWithoutPathExpansion(key_pem_list, std::move(pem_list));
+  onc_object->SetKey(key_pem_list,
+                     base::Value::FromUniquePtrValue(std::move(pem_list)));
   return true;
 }
 
@@ -494,7 +496,8 @@
   url_dict->SetKey(::onc::proxy::kHost, base::Value(host));
   url_dict->SetKey(::onc::proxy::kPort,
                    base::Value(server.host_port_pair().port()));
-  dict->SetWithoutPathExpansion(onc_scheme, std::move(url_dict));
+  dict->SetKey(onc_scheme,
+               base::Value::FromUniquePtrValue(std::move(url_dict)));
 }
 
 // Returns the NetworkConfiugration with |guid| from |network_configs|, or
diff --git a/chromeos/network/proxy/DIR_METADATA b/chromeos/network/proxy/DIR_METADATA
deleted file mode 100644
index 5c6791b3..0000000
--- a/chromeos/network/proxy/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "OS>Systems>Network"
-}
diff --git a/chromeos/resources/DIR_METADATA b/chromeos/resources/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/resources/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/services/DIR_METADATA b/chromeos/services/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/services/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/services/cros_healthd/public/cpp/DIR_METADATA b/chromeos/services/cros_healthd/public/cpp/DIR_METADATA
index 5fd9089..d25365d 100644
--- a/chromeos/services/cros_healthd/public/cpp/DIR_METADATA
+++ b/chromeos/services/cros_healthd/public/cpp/DIR_METADATA
@@ -1,6 +1,3 @@
 buganizer: {
   component_id: 582701
 }
-monorail {
-  component: "OS>Software>Enterprise"
-}
diff --git a/chromeos/services/libassistant/public/mojom/BUILD.gn b/chromeos/services/libassistant/public/mojom/BUILD.gn
index 82944f7..5884e73 100644
--- a/chromeos/services/libassistant/public/mojom/BUILD.gn
+++ b/chromeos/services/libassistant/public/mojom/BUILD.gn
@@ -36,7 +36,7 @@
     "//services/device/public/mojom",
     "//services/media_session/public/mojom",
     "//services/network/public/mojom",
-    "//ui/accessibility/mojom",
+    "//ui/accessibility/mojom:ax_assistant_mojom",
   ]
 
   cpp_typemaps = [
diff --git a/chromeos/services/machine_learning/public/mojom/text_suggester.mojom b/chromeos/services/machine_learning/public/mojom/text_suggester.mojom
index 8fbf544..33c6a0e 100644
--- a/chromeos/services/machine_learning/public/mojom/text_suggester.mojom
+++ b/chromeos/services/machine_learning/public/mojom/text_suggester.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next MinVersion: 1
+// Next MinVersion: 2
 
 // Datatypes and interfaces of text suggester API.
 
@@ -30,8 +30,23 @@
   float normalized_score@1;
 };
 
+// The mode with which a suggestion should be used by a consumer
+[Stable, Extensible]
+enum TextSuggestionMode {
+   // A prediction suggestion is the text predicted after a word. For example
+   // the preceding text could be "how are", and the suggested text would be
+   // "you".
+   [Default] kPrediction = 1,
+
+   // A completion suggestion is similar to a prediction, however the suggestion
+   // also completes any unfinished words in the preceding text. For example,
+   // the preceding text could be "how ar", and the suggested text would be
+   // "e you".
+   kCompletion = 2,
+};
+
 // Defines a query for text suggestions
-// Next ordinal: 2
+// Next ordinal: 3
 [Stable]
 struct TextSuggesterQuery {
   // The text used to generate suggestions
@@ -39,6 +54,9 @@
 
   // Optional: completion candidates for the final word in the text
   array<NextWordCompletionCandidate> next_word_candidates@1;
+
+  // The types of suggestions requested
+  [MinVersion=1] TextSuggestionMode suggestion_mode@2;
 };
 
 // Represents a single generated multi word suggestion candidate.
@@ -53,8 +71,10 @@
 };
 
 // Represents all types of suggestion candidates generated by the service.
+//
 // TODO(crbug/1201949): Note that the Extensible keyword is not supported for
 // union types. We may need to revisit this type in the future.
+//
 // Next ordinal: 1
 [Stable, Extensible]
 union TextSuggestionCandidate {
diff --git a/chromeos/services/media_perception/DIR_METADATA b/chromeos/services/media_perception/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/services/media_perception/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/strings/DIR_METADATA b/chromeos/strings/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/strings/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/system/DIR_METADATA b/chromeos/system/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/system/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/test/DIR_METADATA b/chromeos/test/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/test/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/third_party/DIR_METADATA b/chromeos/third_party/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/third_party/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/tools/DIR_METADATA b/chromeos/tools/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/tools/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/chromeos/tpm/DIR_METADATA b/chromeos/tpm/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/chromeos/tpm/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/components/arc/ime/DIR_METADATA b/components/arc/ime/DIR_METADATA
deleted file mode 100644
index e568bf01..0000000
--- a/components/arc/ime/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Apps>ARC"
-}
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 128133e1..7654d2c3 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -393,13 +393,16 @@
   if (!ShouldSendUpdateToInputMethod())
     return;
 
+  if (!UpdateCursorRect(rect, is_screen_coordinates) &&
+      text_range_ == text_range && text_in_range_ == text_in_range &&
+      selection_range_ == selection_range) {
+    return;
+  }
+
   text_range_ = text_range;
   text_in_range_ = text_in_range;
   selection_range_ = selection_range;
 
-  if (!UpdateCursorRect(rect, is_screen_coordinates))
-    return;
-
   ui::InputMethod* const input_method = GetInputMethod();
   if (input_method)
     input_method->OnCaretBoundsChanged(this);
diff --git a/components/arc/mojom/BUILD.gn b/components/arc/mojom/BUILD.gn
index 9cf3141..76eedfd 100644
--- a/components/arc/mojom/BUILD.gn
+++ b/components/arc/mojom/BUILD.gn
@@ -88,7 +88,7 @@
       "//services/media_session/public/mojom",
       "//services/resource_coordinator/public/mojom",
       "//third_party/blink/public/mojom:android_mojo_bindings",
-      "//ui/accessibility/mojom",
+      "//ui/accessibility/mojom:ax_assistant_mojom",
       "//ui/gfx/geometry/mojom",
       "//url/mojom:url_mojom_gurl",
     ]
diff --git a/components/arc/net/DIR_METADATA b/components/arc/net/DIR_METADATA
deleted file mode 100644
index e568bf01..0000000
--- a/components/arc/net/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Apps>ARC"
-}
diff --git a/components/arc/net/arc_net_host_impl.cc b/components/arc/net/arc_net_host_impl.cc
index d4c5508..d71698f 100644
--- a/components/arc/net/arc_net_host_impl.cc
+++ b/components/arc/net/arc_net_host_impl.cc
@@ -524,8 +524,8 @@
                         base::Value(details->passphrase.value()));
     }
   }
-  properties->SetWithoutPathExpansion(onc::network_config::kWiFi,
-                                      std::move(wifi_dict));
+  properties->SetKey(onc::network_config::kWiFi,
+                     base::Value::FromUniquePtrValue(std::move(wifi_dict)));
 
   std::string user_id_hash = chromeos::LoginState::Get()->primary_user_hash();
   // TODO(crbug.com/730593): Remove SplitOnceCallback() by updating
@@ -737,19 +737,21 @@
   ip_dict->SetKey(onc::ipconfig::kRoutingPrefix, base::Value(32));
   ip_dict->SetKey(onc::ipconfig::kGateway, base::Value(cfg.ipv4_gateway));
 
-  ip_dict->SetWithoutPathExpansion(onc::ipconfig::kNameServers,
-                                   TranslateStringListToValue(cfg.nameservers));
-  ip_dict->SetWithoutPathExpansion(onc::ipconfig::kSearchDomains,
-                                   TranslateStringListToValue(cfg.domains));
-  ip_dict->SetWithoutPathExpansion(
-      onc::ipconfig::kIncludedRoutes,
-      TranslateStringListToValue(cfg.split_include));
-  ip_dict->SetWithoutPathExpansion(
-      onc::ipconfig::kExcludedRoutes,
-      TranslateStringListToValue(cfg.split_exclude));
+  ip_dict->SetKey(onc::ipconfig::kNameServers,
+                  base::Value::FromUniquePtrValue(
+                      TranslateStringListToValue(cfg.nameservers)));
+  ip_dict->SetKey(
+      onc::ipconfig::kSearchDomains,
+      base::Value::FromUniquePtrValue(TranslateStringListToValue(cfg.domains)));
+  ip_dict->SetKey(onc::ipconfig::kIncludedRoutes,
+                  base::Value::FromUniquePtrValue(
+                      TranslateStringListToValue(cfg.split_include)));
+  ip_dict->SetKey(onc::ipconfig::kExcludedRoutes,
+                  base::Value::FromUniquePtrValue(
+                      TranslateStringListToValue(cfg.split_exclude)));
 
-  top_dict->SetWithoutPathExpansion(onc::network_config::kStaticIPConfig,
-                                    std::move(ip_dict));
+  top_dict->SetKey(onc::network_config::kStaticIPConfig,
+                   base::Value::FromUniquePtrValue(std::move(ip_dict)));
 
   // VPN dictionary
   std::unique_ptr<base::DictionaryValue> vpn_dict =
@@ -763,10 +765,11 @@
   arcvpn_dict->SetKey(
       onc::arc_vpn::kTunnelChrome,
       base::Value(cfg.tunnel_chrome_traffic ? "true" : "false"));
-  vpn_dict->SetWithoutPathExpansion(onc::vpn::kArcVpn, std::move(arcvpn_dict));
+  vpn_dict->SetKey(onc::vpn::kArcVpn,
+                   base::Value::FromUniquePtrValue(std::move(arcvpn_dict)));
 
-  top_dict->SetWithoutPathExpansion(onc::network_config::kVPN,
-                                    std::move(vpn_dict));
+  top_dict->SetKey(onc::network_config::kVPN,
+                   base::Value::FromUniquePtrValue(std::move(vpn_dict)));
 
   return top_dict;
 }
diff --git a/components/autofill/core/browser/address_profile_save_manager.cc b/components/autofill/core/browser/address_profile_save_manager.cc
index 9c1dcb32..de060d5 100644
--- a/components/autofill/core/browser/address_profile_save_manager.cc
+++ b/components/autofill/core/browser/address_profile_save_manager.cc
@@ -35,29 +35,15 @@
     return;
   }
 
-  // Otherwise, check if there is already an import process started.
-  if (pending_import_.has_value()) {
-    // If either the observed profile is the same or if the prompt has already
-    // been shown to the user, do nothing and return.
-    if (pending_import_->observed_profile() == observed_profile ||
-        pending_import_->prompt_shown()) {
-      return;
-    }
-  }
+  auto process_ptr = std::make_unique<ProfileImportProcess>(
+      observed_profile, app_locale, url, personal_data_manager_);
 
-  // Create a new pending import process. If there was already an import
-  // process, it is only overwritten if the UI request was not initialized yet.
-  pending_import_ = ProfileImportProcess(
-      observed_profile, personal_data_manager_->GetProfiles(), app_locale, url,
-      personal_data_manager_);
-
-  MaybeOfferSavePrompt();
+  MaybeOfferSavePrompt(std::move(process_ptr));
 }
 
-void AddressProfileSaveManager::MaybeOfferSavePrompt() {
-  DCHECK(pending_import_.has_value());
-
-  switch (pending_import_->import_type()) {
+void AddressProfileSaveManager::MaybeOfferSavePrompt(
+    std::unique_ptr<ProfileImportProcess> import_process) {
+  switch (import_process->import_type()) {
     // If the import was a duplicate, only results in silent updates or if the
     // import of a new profile or a profile update is blocked, finish the
     // process without initiating a user prompt
@@ -66,9 +52,9 @@
     case AutofillProfileImportType::kSuppressedNewProfile:
     case AutofillProfileImportType::kSuppressedConfirmableMergeAndSilentUpdate:
     case AutofillProfileImportType::kSuppressedConfirmableMerge:
-      pending_import_->AcceptWithoutPrompt();
-      FinalizeProfileImport();
-      break;
+      import_process->AcceptWithoutPrompt();
+      FinalizeProfileImport(std::move(import_process));
+      return;
 
     // Both the import of a new profile, or a merge with an existing profile
     // that changes a settings-visible value of an existing profile triggers a
@@ -76,69 +62,73 @@
     case AutofillProfileImportType::kNewProfile:
     case AutofillProfileImportType::kConfirmableMerge:
     case AutofillProfileImportType::kConfirmableMergeAndSilentUpdate:
-      OfferSavePrompt();
-      break;
+      OfferSavePrompt(std::move(import_process));
+      return;
 
     case AutofillProfileImportType::kImportTypeUnspecified:
       NOTREACHED();
-      break;
+      return;
   }
 }
 
-void AddressProfileSaveManager::OfferSavePrompt() {
-  DCHECK(pending_import_.has_value());
+void AddressProfileSaveManager::OfferSavePrompt(
+    std::unique_ptr<ProfileImportProcess> import_process) {
   // The prompt should not have been shown yet.
-  DCHECK(!pending_import_->prompt_shown());
+  DCHECK(import_process->prompt_shown());
 
   // TODO(crbug.com/1175693): Pass the correct SaveAddressProfilePromptOptions
   // below.
 
-  // TODO(crbug.com/1175693): Check pending_import_->set_prompt_was_shown() is
+  // TODO(crbug.com/1175693): Check import_process->set_prompt_was_shown() is
   // always correct even in cases where it conflicts with
   // SaveAddressProfilePromptOptions
 
   // Initiate the prompt and mark it as shown.
-  pending_import_->set_prompt_was_shown();
+  // The import process that carries to state of the current import process is
+  // attached to the callback.
+  import_process->set_prompt_was_shown();
+  ProfileImportProcess* process_ptr = import_process.get();
   client_->ConfirmSaveAddressProfile(
-      pending_import_->import_candidate().value(),
-      base::OptionalOrNullptr(pending_import_->merge_candidate()),
+      process_ptr->import_candidate().value(),
+      base::OptionalOrNullptr(process_ptr->merge_candidate()),
       AutofillClient::SaveAddressProfilePromptOptions{.show_prompt = true},
       base::BindOnce(&AddressProfileSaveManager::OnUserDecision,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(import_process)));
 }
 
 void AddressProfileSaveManager::OnUserDecision(
+    std::unique_ptr<ProfileImportProcess> import_process,
     AutofillClient::SaveAddressProfileOfferUserDecision decision,
     AutofillProfile edited_profile) {
-  DCHECK(pending_import_.has_value());
-  DCHECK(pending_import_->prompt_shown());
+  DCHECK(import_process->prompt_shown());
 
-  pending_import_->SetUserDecision(decision, edited_profile);
-  FinalizeProfileImport();
+  import_process->SetUserDecision(decision, edited_profile);
+  FinalizeProfileImport(std::move(import_process));
 }
 
-void AddressProfileSaveManager::FinalizeProfileImport() {
-  DCHECK(pending_import_.has_value());
+void AddressProfileSaveManager::FinalizeProfileImport(
+    std::unique_ptr<ProfileImportProcess> import_process) {
   DCHECK(personal_data_manager_);
 
   // If the profiles changed at all, reset the full list of AutofillProfiles in
   // the personal data manager.
-  if (pending_import_->ProfilesChanged()) {
+  if (import_process->ProfilesChanged()) {
     std::vector<AutofillProfile> resulting_profiles =
-        pending_import_->GetResultingProfiles();
+        import_process->GetResultingProfiles();
     personal_data_manager_->SetProfiles(&resulting_profiles);
   }
 
-  AutofillProfileImportType import_type = pending_import()->import_type();
+  AutofillProfileImportType import_type = import_process->import_type();
 
   bool accepted_or_edited =
-      pending_import()->user_decision() ==
+      import_process->user_decision() ==
           AutofillClient::SaveAddressProfileOfferUserDecision::kAccepted ||
-      pending_import()->user_decision() ==
+      import_process->user_decision() ==
           AutofillClient::SaveAddressProfileOfferUserDecision::kEdited;
 
   bool declined =
-      pending_import()->user_decision() ==
+      import_process->user_decision() ==
       AutofillClient::SaveAddressProfileOfferUserDecision::kDeclined;
 
   // If the import of a new profile was declined, add a strike for this source
@@ -146,30 +136,29 @@
   if (import_type == AutofillProfileImportType::kNewProfile) {
     if (declined) {
       personal_data_manager_->AddStrikeToBlockNewProfileImportForDomain(
-          pending_import()->form_source_url());
+          import_process->form_source_url());
     } else if (accepted_or_edited) {
       personal_data_manager_->RemoveStrikesToBlockNewProfileImportForDomain(
-          pending_import()->form_source_url());
+          import_process->form_source_url());
     }
   } else if (import_type == AutofillProfileImportType::kConfirmableMerge ||
              import_type ==
                  AutofillProfileImportType::kConfirmableMergeAndSilentUpdate) {
-    DCHECK(pending_import_->merge_candidate().has_value());
+    DCHECK(import_process->merge_candidate().has_value());
     if (declined) {
       personal_data_manager_->AddStrikeToBlockProfileUpdate(
-          pending_import()->merge_candidate()->guid());
+          import_process->merge_candidate()->guid());
     } else if (accepted_or_edited) {
       personal_data_manager_->RemoveStrikesToBlockProfileUpdate(
-          pending_import()->merge_candidate()->guid());
+          import_process->merge_candidate()->guid());
     }
   }
 
-  pending_import_->CollectMetrics();
-  ClearPendingImport();
+  import_process->CollectMetrics();
+  ClearPendingImport(std::move(import_process));
 }
 
-void AddressProfileSaveManager::ClearPendingImport() {
-  pending_import_.reset();
-}
+void AddressProfileSaveManager::ClearPendingImport(
+    std::unique_ptr<ProfileImportProcess> import_process) {}
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/address_profile_save_manager.h b/components/autofill/core/browser/address_profile_save_manager.h
index 39f1d43..55c9bb8 100644
--- a/components/autofill/core/browser/address_profile_save_manager.h
+++ b/components/autofill/core/browser/address_profile_save_manager.h
@@ -43,29 +43,34 @@
  protected:
   // Initiates showing the prompt to the user.
   // This function is virtual to be mocked in tests.
-  virtual void OfferSavePrompt();
+  virtual void OfferSavePrompt(
+      std::unique_ptr<ProfileImportProcess> import_process);
 
   // Clears the pending import. This method can be overloaded to store the
   // history of import processes for testing purposes.
-  virtual void ClearPendingImport();
+  virtual void ClearPendingImport(
+      std::unique_ptr<ProfileImportProcess> import_process);
 
   // Called after the user interaction with the UI is done.
   void OnUserDecision(
+      std::unique_ptr<ProfileImportProcess> import_process,
       AutofillClient::SaveAddressProfileOfferUserDecision decision,
       AutofillProfile edited_profile);
 
-  ProfileImportProcess* pending_import() {
-    return base::OptionalOrNullptr(pending_import_);
+  PersonalDataManager* personal_data_manager() {
+    return personal_data_manager_;
   }
 
  private:
   // Called to initiate the actual storing of a profile.
   // Verifies that the profile was actually imported.
-  void FinalizeProfileImport();
+  void FinalizeProfileImport(
+      std::unique_ptr<ProfileImportProcess> import_process);
 
   // Called to make the final decision if the UI should be shown, or if the
   // import process should be continued silently.
-  void MaybeOfferSavePrompt();
+  void MaybeOfferSavePrompt(
+      std::unique_ptr<ProfileImportProcess> import_process);
 
   // A pointer to the autofill client. It is assumed that the client outlives
   // the instance of this class
@@ -75,9 +80,6 @@
   // web database.
   PersonalDataManager* const personal_data_manager_{nullptr};
 
-  // Data including the request id for the currently ongoing profile import.
-  absl::optional<ProfileImportProcess> pending_import_;
-
   base::WeakPtrFactory<AddressProfileSaveManager> weak_ptr_factory_{this};
 };
 
diff --git a/components/autofill/core/browser/address_profile_save_manager_unittest.cc b/components/autofill/core/browser/address_profile_save_manager_unittest.cc
index 76f00c8..951b7166 100644
--- a/components/autofill/core/browser/address_profile_save_manager_unittest.cc
+++ b/components/autofill/core/browser/address_profile_save_manager_unittest.cc
@@ -58,23 +58,44 @@
                                 PersonalDataManager* personal_data_manager);
 
   // Mocks the function that initiates the UI prompt for testing purposes.
-  MOCK_METHOD(void, OfferSavePrompt, (), (override));
+  MOCK_METHOD(void,
+              OfferSavePrompt,
+              (std::unique_ptr<ProfileImportProcess>),
+              (override));
 
   // Returns a copy of the last finished import process or 'absl::nullopt' if no
   // import process was finished.
   ProfileImportProcess* last_import();
 
-  void OnUserDecisionForTesting(UserDecision decision,
-                                AutofillProfile edited_profile) {
-    pending_import()->set_prompt_was_shown();
-    OnUserDecision(decision, edited_profile);
+  void OnUserDecisionForTesting(
+      std::unique_ptr<ProfileImportProcess> import_process,
+      UserDecision decision,
+      AutofillProfile edited_profile) {
+    if (profile_added_while_waiting_for_user_response_) {
+      personal_data_manager()->AddProfile(
+          profile_added_while_waiting_for_user_response_.value());
+    }
+
+    import_process->set_prompt_was_shown();
+    OnUserDecision(std::move(import_process), decision, edited_profile);
+  }
+
+  void SetProfileThatIsAddedInWhileWaitingForUserResponse(
+      const AutofillProfile& profile) {
+    profile_added_while_waiting_for_user_response_ = profile;
   }
 
  protected:
-  void ClearPendingImport() override;
+  void ClearPendingImport(
+      std::unique_ptr<ProfileImportProcess> import_process) override;
   // Profile that is passed from the emulated UI respones in case the user
   // edited the import candidate.
-  absl::optional<ProfileImportProcess> last_import_;
+  std::unique_ptr<ProfileImportProcess> last_import_;
+
+  // If set, this is a profile that is added in between the import operation
+  // while the response from the user is pending.
+  absl::optional<AutofillProfile>
+      profile_added_while_waiting_for_user_response_;
 };
 
 TestAddressProfileSaveManager::TestAddressProfileSaveManager(
@@ -82,15 +103,14 @@
     PersonalDataManager* personal_data_manager)
     : AddressProfileSaveManager(client, personal_data_manager) {}
 
-void TestAddressProfileSaveManager::ClearPendingImport() {
-  if (pending_import()) {
-    last_import_ = base::OptionalFromPtr(pending_import());
-  }
-  AddressProfileSaveManager::ClearPendingImport();
+void TestAddressProfileSaveManager::ClearPendingImport(
+    std::unique_ptr<ProfileImportProcess> import_process) {
+  last_import_ = std::move(import_process);
+  AddressProfileSaveManager::ClearPendingImport(std::move(import_process));
 }
 
 ProfileImportProcess* TestAddressProfileSaveManager::last_import() {
-  return base::OptionalOrNullptr(last_import_);
+  return last_import_.get();
 }
 
 // Definition of a test scenario.
@@ -109,6 +129,7 @@
       expected_edited_types_for_metrics;
   bool new_profiles_suppresssed_for_domain;
   std::vector<std::string> blocked_guids_for_updates;
+  absl::optional<AutofillProfile> profile_to_be_added_while_waiting;
 };
 
 class AddressProfileSaveManagerTest : public testing::Test {
@@ -150,6 +171,11 @@
                                              &mock_personal_data_manager_);
   base::HistogramTester histogram_tester;
 
+  if (test_scenario.profile_to_be_added_while_waiting) {
+    save_manager.SetProfileThatIsAddedInWhileWaitingForUserResponse(
+        test_scenario.profile_to_be_added_while_waiting.value());
+  }
+
   // If the domain is blocked for new imports, use the defined limit for the
   // initial strikes. Otherwise, use 1.
   int initial_strikes =
@@ -173,14 +199,16 @@
 
   // Set up the expectation and response for if a prompt should be shown.
   if (test_scenario.is_prompt_expected) {
-    EXPECT_CALL(save_manager, OfferSavePrompt())
+    EXPECT_CALL(save_manager, OfferSavePrompt(testing::_))
         .Times(1)
-        .WillOnce(testing::InvokeWithoutArgs([&]() {
-          save_manager.OnUserDecisionForTesting(test_scenario.user_decision,
-                                                test_scenario.edited_profile);
-        }));
+        .WillOnce(testing::WithArgs<0>(
+            [&](std::unique_ptr<ProfileImportProcess> import_process) {
+              save_manager.OnUserDecisionForTesting(
+                  std::move(import_process), test_scenario.user_decision,
+                  test_scenario.edited_profile);
+            }));
   } else {
-    EXPECT_CALL(save_manager, OfferSavePrompt()).Times(0);
+    EXPECT_CALL(save_manager, OfferSavePrompt).Times(0);
   }
 
   // Set the existing profiles to the personal data manager.
@@ -203,7 +231,8 @@
   for (const auto* profile : mock_personal_data_manager_.GetProfiles())
     final_profiles.push_back(*profile);
 
-  EXPECT_EQ(test_scenario.expected_final_profiles, final_profiles);
+  EXPECT_THAT(test_scenario.expected_final_profiles,
+              testing::UnorderedElementsAreArray(final_profiles));
 
   // Test that the merge and import candidates are correct.
   EXPECT_EQ(test_scenario.merge_candidate, last_import->merge_candidate());
@@ -318,6 +347,29 @@
   TestImportScenario(test_scenario);
 }
 
+// Test that a profile is correctly imported when no other profile is stored
+// yet but another profile is added while waiting for the user response.
+TEST_F(AddressProfileSaveManagerTest, SaveNewProfile_ProfileAddedWhileWaiting) {
+  AutofillProfile observed_profile = test::StandardProfile();
+  AutofillProfile profile_added_while_waiting =
+      test::DifferentFromStandardProfile();
+
+  ImportScenarioTestCase test_scenario{
+      .existing_profiles = {},
+      .observed_profile = observed_profile,
+      .is_prompt_expected = true,
+      .user_decision = UserDecision::kAccepted,
+      .expected_import_type = AutofillProfileImportType::kNewProfile,
+      .is_profile_change_expected = true,
+      .merge_candidate = absl::nullopt,
+      .import_candidate = observed_profile,
+      .expected_final_profiles = {observed_profile,
+                                  profile_added_while_waiting},
+      .profile_to_be_added_while_waiting = profile_added_while_waiting};
+
+  TestImportScenario(test_scenario);
+}
+
 // Test that a profile is not imported and that the user is not prompted if the
 // domain is blocked for imorting new profiles.
 TEST_F(AddressProfileSaveManagerTest, SaveNewProfileOnBlockedDomain) {
diff --git a/components/autofill/core/browser/autofill_profile_import_process.cc b/components/autofill/core/browser/autofill_profile_import_process.cc
index 9ab50b6..274f2af 100644
--- a/components/autofill/core/browser/autofill_profile_import_process.cc
+++ b/components/autofill/core/browser/autofill_profile_import_process.cc
@@ -25,7 +25,6 @@
 
 ProfileImportProcess::ProfileImportProcess(
     const AutofillProfile& observed_profile,
-    const std::vector<AutofillProfile*>& existing_profiles,
     const std::string& app_locale,
     const GURL& form_source_url,
     const PersonalDataManager* personal_data_manager)
@@ -34,7 +33,7 @@
       app_locale_(app_locale),
       form_source_url_(form_source_url),
       personal_data_manager_(personal_data_manager) {
-  DetermineProfileImportType(existing_profiles, app_locale);
+  DetermineProfileImportType();
 }
 
 ProfileImportProcess::ProfileImportProcess(const ProfileImportProcess&) =
@@ -49,10 +48,8 @@
   return prompt_shown_;
 }
 
-void ProfileImportProcess::DetermineProfileImportType(
-    const std::vector<AutofillProfile*>& existing_profiles,
-    const std::string& app_locale) {
-  AutofillProfileComparator comparator(app_locale);
+void ProfileImportProcess::DetermineProfileImportType() {
+  AutofillProfileComparator comparator(app_locale_);
   bool is_mergeable_with_existing_profile = false;
 
   new_profiles_suppressed_for_domain_ =
@@ -61,11 +58,16 @@
                 form_source_url_)
           : false;
 
+  int number_of_unchanged_profiles = 0;
+
+  const std::vector<AutofillProfile*> existing_profiles =
+      personal_data_manager_->GetProfiles();
+
   for (const auto* existing_profile : existing_profiles) {
     // If the existing profile is not mergeable with the observed profile, the
     // existing profile is not altered by this import.
     if (!comparator.AreMergeable(*existing_profile, observed_profile_)) {
-      unchanged_profiles_.emplace_back(*existing_profile);
+      ++number_of_unchanged_profiles;
       continue;
     }
 
@@ -78,8 +80,8 @@
     // The return value of |MergeDataFrom()| indicates if the existing profile
     // was changed at all during that merge.
     AutofillProfile merged_profile = *existing_profile;
-    if (!merged_profile.MergeDataFrom(observed_profile_, app_locale)) {
-      unchanged_profiles_.emplace_back(*existing_profile);
+    if (!merged_profile.MergeDataFrom(observed_profile_, app_locale_)) {
+      ++number_of_unchanged_profiles;
       continue;
     }
 
@@ -111,7 +113,7 @@
       } else {
         // If there is already a merge candidate, the existing profile is not
         // supposed to be changed.
-        unchanged_profiles_.emplace_back(*existing_profile);
+        ++number_of_unchanged_profiles;
       }
       continue;
     }
@@ -155,27 +157,36 @@
   // At this point, all existing profiles are either unchanged, updated and/or
   // one is the merge candidate.
   DCHECK_EQ(existing_profiles.size(),
-            unchanged_profiles_.size() + updated_profiles_.size() +
+            number_of_unchanged_profiles + updated_profiles_.size() +
                 (merge_candidate_.has_value() ? 1 : 0));
   DCHECK_NE(import_type_, AutofillProfileImportType::kImportTypeUnspecified);
 }
 
 std::vector<AutofillProfile> ProfileImportProcess::GetResultingProfiles() {
-  std::vector<AutofillProfile> resulting_profiles;
-
   // At this point, a user decision must have been supplied.
   DCHECK_NE(user_decision_, UserDecision::kUndefined);
 
-  // The unchanged and updated profiles should be added unconditionally.
-  resulting_profiles.insert(resulting_profiles.end(),
-                            unchanged_profiles_.begin(),
-                            unchanged_profiles_.end());
-  resulting_profiles.insert(resulting_profiles.end(), updated_profiles_.begin(),
-                            updated_profiles_.end());
+  std::vector<AutofillProfile> resulting_profiles;
+  std::set<std::string> guids_of_changed_profiles;
+
+  // Add all updated profiles.
+  for (const auto& updated_profile : updated_profiles_) {
+    resulting_profiles.push_back(updated_profile);
+    guids_of_changed_profiles.insert(updated_profile.guid());
+  }
 
   // If there is a confirmed import candidate, add it.
   if (confirmed_import_candidate_.has_value()) {
     resulting_profiles.emplace_back(confirmed_import_candidate_.value());
+    guids_of_changed_profiles.insert(confirmed_import_candidate_->guid());
+  }
+
+  // Add all other profiles that are currently available in the personal data
+  // manager.
+  for (const auto* unchanged_profile : personal_data_manager_->GetProfiles()) {
+    if (guids_of_changed_profiles.count(unchanged_profile->guid()) == 0) {
+      resulting_profiles.push_back(*unchanged_profile);
+    }
   }
 
   return resulting_profiles;
@@ -212,11 +223,7 @@
     // that silent updates are not performed.
     case UserDecision::kDeclined:
     case UserDecision::kIgnored:
-      confirmed_import_candidate_ = merge_candidate_;
-      break;
-
     case UserDecision::kNever:
-      confirmed_import_candidate_ = merge_candidate_;
       break;
 
     case UserDecision::kUndefined:
diff --git a/components/autofill/core/browser/autofill_profile_import_process.h b/components/autofill/core/browser/autofill_profile_import_process.h
index 9b7be0b..9f9804c7 100644
--- a/components/autofill/core/browser/autofill_profile_import_process.h
+++ b/components/autofill/core/browser/autofill_profile_import_process.h
@@ -67,7 +67,6 @@
 class ProfileImportProcess {
  public:
   ProfileImportProcess(const AutofillProfile& observed_profile,
-                       const std::vector<AutofillProfile*>& existing_profiles,
                        const std::string& app_locale,
                        const GURL& form_source_url,
                        const PersonalDataManager* personal_data_manager);
@@ -147,9 +146,7 @@
   // Determines the import type of |observed_profile_| with respect to
   // |existing_profiles|. Only the first profile in |existing_profiles| becomes
   // a merge candidate in case there is a confirmable merge.
-  void DetermineProfileImportType(
-      const std::vector<AutofillProfile*>& existing_profiles,
-      const std::string& app_locale);
+  void DetermineProfileImportType();
 
   // An id to identify an import request.
   AutofillProfileImportId import_id_;
@@ -160,10 +157,6 @@
   // The profile as it has been observed on form submission.
   AutofillProfile observed_profile_;
 
-  // Profiles that are not mergeable with the observed profile or for which
-  // the merge does not result in any change.
-  std::vector<AutofillProfile> unchanged_profiles_;
-
   // Profiles that are silently updateable with the observed profile.
   std::vector<AutofillProfile> updated_profiles_;
 
diff --git a/components/autofill/core/browser/autofill_profile_import_process_unittest.cc b/components/autofill/core/browser/autofill_profile_import_process_unittest.cc
index 624d3c9..c83851b0 100644
--- a/components/autofill/core/browser/autofill_profile_import_process_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_import_process_unittest.cc
@@ -42,9 +42,9 @@
 // Test that two subsequently created `ProfileImportProcess`s have distinct ids.
 TEST_F(AutofillProfileImportProcessTest, DistinctIds) {
   AutofillProfile empty_profile;
-  ProfileImportProcess import_data1(empty_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data1(empty_profile, "en_US", url_,
                                     &personal_data_manager_);
-  ProfileImportProcess import_data2(empty_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data2(empty_profile, "en_US", url_,
                                     &personal_data_manager_);
 
   // The import ids should be distinct.
@@ -61,9 +61,12 @@
 TEST_F(AutofillProfileImportProcessTest, ImportFirstProfile_UserAccepts) {
   AutofillProfile observed_profile = test::StandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the scenario that there aren't any other
   // stored profiles yet.
-  ProfileImportProcess import_data(observed_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
                                    &personal_data_manager_);
 
   // Simulate the acceptance of the save prompt.
@@ -83,11 +86,14 @@
 TEST_F(AutofillProfileImportProcessTest, ImportFirstProfile_ImportIsBlocked) {
   AutofillProfile observed_profile = test::StandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   BlockDomainForNewProfiles(url_);
 
   // Create the import process for the scenario that there aren't any other
   // stored profiles yet.
-  ProfileImportProcess import_data(observed_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
                                    &personal_data_manager_);
 
   // The user is not asked.
@@ -108,9 +114,12 @@
        ImportFirstProfile_UserAcceptsWithEdits) {
   AutofillProfile observed_profile = test::StandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the scenario that there aren't any other
   // stored profiles yet.
-  ProfileImportProcess import_data(observed_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
                                    &personal_data_manager_);
 
   // Simulate that the user accepts the save prompt but only after editing the
@@ -134,9 +143,12 @@
 TEST_F(AutofillProfileImportProcessTest, ImportFirstProfile_UserRejects) {
   AutofillProfile observed_profile = test::StandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the scenario that there aren't any other
   // stored profiles yet.
-  ProfileImportProcess import_data(observed_profile, {}, "en_US", url_,
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
                                    &personal_data_manager_);
 
   // Simulate the decline of the user.
@@ -156,12 +168,14 @@
 // existing profile.
 TEST_F(AutofillProfileImportProcessTest, ImportDuplicateProfile) {
   AutofillProfile observed_profile = test::StandardProfile();
-  AutofillProfile existing_profile = observed_profile;
+
+  std::vector<AutofillProfile> existing_profiles = {observed_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
 
   // Create the import process for the scenario that the observed profile is an
   // exact copy of an already existing one.
-  ProfileImportProcess import_data(observed_profile, {&existing_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the import of a duplicate is determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -175,7 +189,7 @@
   EXPECT_FALSE(import_data.ProfilesChanged());
 
   EXPECT_THAT(import_data.GetResultingProfiles(),
-              testing::UnorderedElementsAre(existing_profile));
+              testing::UnorderedElementsAre(existing_profiles.at(0)));
 }
 
 // Tests the import of a profile that is an exact duplicate of an already
@@ -191,11 +205,13 @@
   AutofillProfile distinct_existing_profile =
       test::DifferentFromStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {duplicate_existing_profile,
+                                                    distinct_existing_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the two already existing profiles.
-  ProfileImportProcess import_data(
-      observed_profile,
-      {&duplicate_existing_profile, &distinct_existing_profile}, "en_US", url_,
-      &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -220,10 +236,13 @@
   // The profile should be mergeable with the observed profile.
   AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the scenario that a profile that is mergeable
   // with the observed profile already exists.
-  ProfileImportProcess import_data(observed_profile, {&mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -258,10 +277,13 @@
   // The profile should be mergeable with the observed profile.
   AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process for the scenario that a profile that is mergeable
   // with the observed profile already exists.
-  ProfileImportProcess import_data(observed_profile, {&mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -294,10 +316,13 @@
   // This is just another completely different profile.
   AutofillProfile distinct_profile = test::DifferentFromStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {mergeable_profile,
+                                                    distinct_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create an import data instance for the observed profile and determine the
   // import type for the case that there are no already existing profiles.
   ProfileImportProcess import_data(observed_profile,
-                                   {&mergeable_profile, &distinct_profile},
                                    "en_US", url_, &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
@@ -329,10 +354,13 @@
   // The profile should be mergeable with the observed profile.
   AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create an import data instance for the observed profile and determine the
   // import type for the case that there are no already existing profiles.
-  ProfileImportProcess import_data(observed_profile, {&mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -366,10 +394,13 @@
   // The profile should be updateable with the observed profile.
   AutofillProfile updateable_profile = test::UpdateableStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {updateable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+  //
   // Create the import process for the scenario that there is an existing
   // profile that is updateable with the observed profile.
-  ProfileImportProcess import_data(observed_profile, {&updateable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -408,10 +439,13 @@
   // This profile should be mergeable with the observed profile.
   AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {updateable_profile,
+                                                    mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process with a mergeable and a updateable profile..
-  ProfileImportProcess import_data(observed_profile,
-                                   {&updateable_profile, &mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -452,10 +486,13 @@
   // This profile should be mergeable with the observed profile.
   AutofillProfile mergeable_profile = test::SubsetOfStandardProfile();
 
+  std::vector<AutofillProfile> existing_profiles = {updateable_profile,
+                                                    mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process with a mergeable and a updateable profile..
-  ProfileImportProcess import_data(observed_profile,
-                                   {&updateable_profile, &mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
@@ -498,10 +535,13 @@
 
   BlockProfileForUpdates(mergeable_profile);
 
+  std::vector<AutofillProfile> existing_profiles = {updateable_profile,
+                                                    mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process with a mergeable and an updateable profile..
-  ProfileImportProcess import_data(observed_profile,
-                                   {&updateable_profile, &mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(
@@ -541,9 +581,12 @@
 
   BlockProfileForUpdates(mergeable_profile);
 
+  std::vector<AutofillProfile> existing_profiles = {mergeable_profile};
+  personal_data_manager_.SetProfiles(&existing_profiles);
+
   // Create the import process with a mergeable profile.
-  ProfileImportProcess import_data(observed_profile, {&mergeable_profile},
-                                   "en_US", url_, &personal_data_manager_);
+  ProfileImportProcess import_data(observed_profile, "en_US", url_,
+                                   &personal_data_manager_);
 
   // Test that the type of import was determined correctly.
   EXPECT_EQ(import_data.import_type(),
diff --git a/components/autofill/core/browser/strike_database_integrator_base.cc b/components/autofill/core/browser/strike_database_integrator_base.cc
index 6d63e2ee..b7109648 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.cc
+++ b/components/autofill/core/browser/strike_database_integrator_base.cc
@@ -140,10 +140,6 @@
   }
   std::vector<std::string> expired_keys;
   for (auto entry : strike_database_->GetStrikeCache()) {
-    // Only consider keys from the current strike database integrator.
-    if (strike_database_->GetPrefixFromKey(entry.first) != GetProjectPrefix()) {
-      continue;
-    }
     if (GetEntryAge(entry.second) > GetExpiryTimeDelta().value()) {
       if (strike_database_->GetStrikes(entry.first) > 0) {
         expired_keys.push_back(entry.first);
diff --git a/components/autofill/core/browser/strike_database_integrator_base.h b/components/autofill/core/browser/strike_database_integrator_base.h
index 29003111..0a8f115 100644
--- a/components/autofill/core/browser/strike_database_integrator_base.h
+++ b/components/autofill/core/browser/strike_database_integrator_base.h
@@ -94,21 +94,19 @@
   FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest,
                            StrikeDatabaseEmptyOnAutofillRemoveEverything);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-                           ClearStrikesForKeys);
-  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-                           GetKeyForStrikeDatabaseIntegratorUniqueIdTest);
-  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-                           IdFromKey);
-  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
                            NonExpiringStrikesDoNotExpire);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-                           RemoveExpiredStrikesOnlyConsidersCurrentIntegrator);
-  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
                            RemoveExpiredStrikesTest);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-                           RemoveExpiredStrikesTestLogsUMA);
+                           GetKeyForStrikeDatabaseIntegratorUniqueIdTest);
   FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
                            RemoveExpiredStrikesUniqueIdTest);
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+                           RemoveExpiredStrikesTestLogsUMA);
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+                           IdFromKey);
+  FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
+                           ClearStrikesForKeys);
   friend class SaveCardInfobarEGTestHelper;
   friend class StrikeDatabaseTest;
   friend class StrikeDatabaseTester;
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
index a3e5b90..80dd5d33 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.cc
@@ -8,6 +8,7 @@
 
 namespace autofill {
 
+const char kProjectPrefix[] = "StrikeDatabaseIntegratorTest";
 const int kMaxStrikesLimit = 6;
 
 StrikeDatabaseIntegratorTestStrikeDatabase::
@@ -25,21 +26,11 @@
 }
 
 StrikeDatabaseIntegratorTestStrikeDatabase::
-    StrikeDatabaseIntegratorTestStrikeDatabase(
-        StrikeDatabase* strike_database,
-        absl::optional<base::TimeDelta> expiry_time_delta,
-        std::string& project_prefix)
-    : StrikeDatabaseIntegratorTestStrikeDatabase(strike_database,
-                                                 expiry_time_delta) {
-  project_prefix_ = project_prefix;
-}
-
-StrikeDatabaseIntegratorTestStrikeDatabase::
     ~StrikeDatabaseIntegratorTestStrikeDatabase() = default;
 
 std::string StrikeDatabaseIntegratorTestStrikeDatabase::GetProjectPrefix()
     const {
-  return project_prefix_;
+  return kProjectPrefix;
 }
 
 int StrikeDatabaseIntegratorTestStrikeDatabase::GetMaxStrikesLimit() const {
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
index 33053e76..1c132af 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database.h
@@ -23,12 +23,6 @@
       absl::optional<base::TimeDelta> expiry_time_delta);
   explicit StrikeDatabaseIntegratorTestStrikeDatabase(
       StrikeDatabase* strike_database);
-  // This constructor initializes the TestStrikeDatabase with a non-default
-  // project prefix.
-  StrikeDatabaseIntegratorTestStrikeDatabase(
-      StrikeDatabase* strike_database,
-      absl::optional<base::TimeDelta> expiry_time_delta,
-      std::string& project_prefix);
   ~StrikeDatabaseIntegratorTestStrikeDatabase() override;
 
   absl::optional<size_t> GetMaximumEntries() const override;
@@ -48,7 +42,6 @@
 
   absl::optional<size_t> maximum_entries_ = 10;
   absl::optional<size_t> maximum_entries_after_cleanup_ = 5;
-  std::string project_prefix_ = "StrikeDatabaseIntegratorTest";
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
index 0b9349f..8cb5f99 100644
--- a/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
+++ b/components/autofill/core/browser/strike_database_integrator_test_strike_database_unittest.cc
@@ -206,38 +206,6 @@
       11, 1);
 }
 
-// This test verifies correctness of http://crbug/1206176.
-TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
-       RemoveExpiredStrikesOnlyConsidersCurrentIntegrator) {
-  autofill::TestAutofillClock test_clock;
-  test_clock.SetNow(AutofillClock::Now());
-  // Create a second test integrator, but with a different project prefix name,
-  // and whose strikes explicitly do not expire.
-  std::string other_project_prefix = "DifferentProjectPrefix";
-  std::unique_ptr<StrikeDatabaseIntegratorTestStrikeDatabase>
-      other_strike_database =
-          std::make_unique<StrikeDatabaseIntegratorTestStrikeDatabase>(
-              strike_database_service_.get(),
-              /*expiry_time_micros=*/base::nullopt, other_project_prefix);
-
-  // Add a strike to both integrators.
-  strike_database_->AddStrike();
-  EXPECT_EQ(1, strike_database_->GetStrikes());
-  other_strike_database->AddStrike();
-  EXPECT_EQ(1, other_strike_database->GetStrikes());
-
-  // Advance clock to past expiry time for |strike_database_|.
-  test_clock.Advance(strike_database_->GetExpiryTimeDelta().value() +
-                     base::TimeDelta::FromMicroseconds(1));
-
-  // Attempt to expire strikes. Only |strike_database_|'s keys should be
-  // affected.
-  strike_database_->RemoveExpiredStrikes();
-  other_strike_database->RemoveExpiredStrikes();
-  EXPECT_EQ(0, strike_database_->GetStrikes());
-  EXPECT_EQ(1, other_strike_database->GetStrikes());
-}
-
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        GetKeyForStrikeDatabaseIntegratorUniqueIdTest) {
   strike_database_->SetUniqueIdsRequired(true);
diff --git a/components/autofill_assistant/browser/client_context.cc b/components/autofill_assistant/browser/client_context.cc
index 1fcacaee..e3cbab6 100644
--- a/components/autofill_assistant/browser/client_context.cc
+++ b/components/autofill_assistant/browser/client_context.cc
@@ -49,6 +49,9 @@
   if (trigger_context.GetDirectAction()) {
     proto_.set_is_direct_action(true);
   }
+  if (trigger_context.GetInChromeTriggered()) {
+    proto_.set_is_in_chrome_triggered(true);
+  }
 
   // TODO(b/156882027): Add an integration test for accounts handling.
   auto caller_email = trigger_context.GetScriptParameters().GetCallerEmail();
diff --git a/components/autofill_assistant/browser/client_context_unittest.cc b/components/autofill_assistant/browser/client_context_unittest.cc
index f56d5c8..19ae517 100644
--- a/components/autofill_assistant/browser/client_context_unittest.cc
+++ b/components/autofill_assistant/browser/client_context_unittest.cc
@@ -102,13 +102,15 @@
        /* is_cct = */ true,
        /* onboarding_shown = */ true,
        /* is_direct_action = */ true,
-       /* initial_url = */ "https://www.example.com"});
+       /* initial_url = */ "https://www.example.com",
+       /* is_in_chrome_triggered = */ true});
 
   auto actual_client_context = client_context.AsProto();
   EXPECT_THAT(actual_client_context.experiment_ids(), Eq("1,2,3"));
   EXPECT_THAT(actual_client_context.is_cct(), Eq(true));
   EXPECT_THAT(actual_client_context.is_onboarding_shown(), Eq(true));
   EXPECT_THAT(actual_client_context.is_direct_action(), Eq(true));
+  EXPECT_THAT(actual_client_context.is_in_chrome_triggered(), Eq(true));
   EXPECT_THAT(actual_client_context.accessibility_enabled(), Eq(true));
   EXPECT_THAT(actual_client_context.experiment_ids(), Eq("1,2,3"));
   EXPECT_THAT(actual_client_context.signed_into_chrome_status(),
@@ -138,7 +140,8 @@
                          /* is_cct = */ true,
                          /* onboarding_shown = */ true,
                          /* is_direct_action = */ true,
-                         /* initial_url = */ "https://www.example.com"});
+                         /* initial_url = */ "https://www.example.com",
+                         /* is_in_chrome_triggered = */ false});
 
   actual_client_context = client_context.AsProto();
   EXPECT_FALSE(actual_client_context.has_window_size());
@@ -159,7 +162,8 @@
        /* is_cct = */ false,
        /* onboarding_shown = */ false,
        /* is_direct_action = */ false,
-       /* initial_url = */ "https://www.example.com"});
+       /* initial_url = */ "https://www.example.com",
+       /* is_in_chrome_triggered = */ false});
   EXPECT_THAT(client_context.AsProto().accounts_matching_status(),
               Eq(ClientContextProto::ACCOUNTS_MATCHING));
 
@@ -170,7 +174,8 @@
        /* is_cct = */ false,
        /* onboarding_shown = */ false,
        /* is_direct_action = */ false,
-       /* initial_url = */ "https://www.example.com"});
+       /* initial_url = */ "https://www.example.com",
+       /* is_in_chrome_triggered = */ false});
   EXPECT_THAT(client_context.AsProto().accounts_matching_status(),
               Eq(ClientContextProto::ACCOUNTS_NOT_MATCHING));
 }
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index ffcc79fb..9a96c55 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -55,6 +55,10 @@
   // True if the script was triggered by a direct action.
   optional bool is_direct_action = 9;
 
+  // True if this an in-Chrome triggered flow, rather than an externally
+  // triggered one.
+  optional bool is_in_chrome_triggered = 17;
+
   message DeviceContextProto {
     message VersionProto {
       // The Android SDK version of the device.
@@ -606,7 +610,7 @@
   // An identifier for the type of trigger UI this trigger represents, for UKM.
   optional TriggerUIType trigger_ui_type = 5;
 
-  reserved 2;
+  reserved 2, 6;
 }
 
 // Set of TriggerUIType to group UKM metrics by.
@@ -615,10 +619,19 @@
 // tools/metrics/histograms/enums.xml
 enum TriggerUIType {
   UNSPECIFIED_TRIGGER_UI_TYPE = 0;
+
+  // Explicit trigger requests by some external trigger surface, i.e., a link
+  // or button.
   CART_FIRST_TIME_USER = 1;
   CART_RETURNING_USER = 2;
   CHECKOUT_FIRST_TIME_USER = 3;
   CHECKOUT_RETURNING_USER = 4;
+
+  // Implicit trigger requests started by Chrome itself.
+  IN_CHROME_CART_FIRST_TIME_USER = 5;
+  IN_CHROME_CART_RETURNING_USER = 6;
+  IN_CHROME_CHECKOUT_FIRST_TIME_USER = 7;
+  IN_CHROME_CHECKOUT_RETURNING_USER = 8;
 }
 
 message TriggerScriptConditionProto {
diff --git a/components/autofill_assistant/browser/starter.cc b/components/autofill_assistant/browser/starter.cc
index 1d7f56b5..22b5a72 100644
--- a/components/autofill_assistant/browser/starter.cc
+++ b/components/autofill_assistant/browser/starter.cc
@@ -299,7 +299,8 @@
                               /* is_cct = */ is_custom_tab_,
                               /* onboarding_shown = */ false,
                               /* is_direct_action = */ false,
-                              /* initial_url = */ std::string()}));
+                              /* initial_url = */ std::string(),
+                              /* is_in_chrome_triggered = */ true}));
 }
 
 bool Starter::IsStartupPending() const {
diff --git a/components/autofill_assistant/browser/starter_unittest.cc b/components/autofill_assistant/browser/starter_unittest.cc
index 67d65362..f5b6ec8 100644
--- a/components/autofill_assistant/browser/starter_unittest.cc
+++ b/components/autofill_assistant/browser/starter_unittest.cc
@@ -638,6 +638,7 @@
             GetTriggerScriptsRequestProto request;
             ASSERT_TRUE(request.ParseFromString(request_body));
             EXPECT_THAT(request.url(), Eq(GURL(kExampleDeeplink)));
+            EXPECT_FALSE(request.client_context().is_in_chrome_triggered());
             std::move(callback).Run(net::HTTP_OK,
                                     CreateTriggerScriptResponseForTest());
           }));
@@ -982,6 +983,7 @@
             ASSERT_TRUE(request.ParseFromString(request_body));
             EXPECT_THAT(request.url(),
                         Eq(GURL("https://www.some-website.com/cart")));
+            EXPECT_TRUE(request.client_context().is_in_chrome_triggered());
             std::move(callback).Run(net::HTTP_OK,
                                     CreateTriggerScriptResponseForTest());
           }));
diff --git a/components/autofill_assistant/browser/startup_util_unittest.cc b/components/autofill_assistant/browser/startup_util_unittest.cc
index 859b1fc..1682479 100644
--- a/components/autofill_assistant/browser/startup_util_unittest.cc
+++ b/components/autofill_assistant/browser/startup_util_unittest.cc
@@ -82,10 +82,10 @@
     {"ORIGINAL_DEEPLINK", "https://www.example.com"}};
 
 const TriggerContext::Options kDefaultCCTOptions = {
-    std::string(), /* is_cct = */ true, false, false, std::string()};
+    std::string(), /* is_cct = */ true, false, false, std::string(), false};
 
 const TriggerContext::Options kDefaultNonCCTOptions = {
-    std::string(), /* is_cct = */ false, false, false, std::string()};
+    std::string(), /* is_cct = */ false, false, false, std::string(), false};
 
 // The set of feature combinations to test.
 const TestFeatureConfig kTestFeatureConfigs[] = {
@@ -416,7 +416,7 @@
                   std::map<std::string, std::string>{
                       {"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}}),
               {std::string(), /* is_cct = */ true, false, false,
-               /* initial_url = */ "https://www.example.com"}},
+               /* initial_url = */ "https://www.example.com", false}},
           {.msbb_setting_enabled = true,
            .proactive_help_setting_enabled = true,
            .feature_module_installed = true}),
diff --git a/components/autofill_assistant/browser/trigger_context.cc b/components/autofill_assistant/browser/trigger_context.cc
index b701ce9..0cecc56a 100644
--- a/components/autofill_assistant/browser/trigger_context.cc
+++ b/components/autofill_assistant/browser/trigger_context.cc
@@ -12,12 +12,14 @@
                                  bool _is_cct,
                                  bool _onboarding_shown,
                                  bool _is_direct_action,
-                                 const std::string& _initial_url)
+                                 const std::string& _initial_url,
+                                 bool _is_in_chrome_triggered)
     : experiment_ids(_experiment_ids),
       is_cct(_is_cct),
       onboarding_shown(_onboarding_shown),
       is_direct_action(_is_direct_action),
-      initial_url(_initial_url) {}
+      initial_url(_initial_url),
+      is_in_chrome_triggered(_is_in_chrome_triggered) {}
 
 TriggerContext::Options::Options() = default;
 TriggerContext::Options::~Options() = default;
@@ -33,7 +35,8 @@
                      options.is_cct,
                      options.onboarding_shown,
                      options.is_direct_action,
-                     options.initial_url) {}
+                     options.initial_url,
+                     options.is_in_chrome_triggered) {}
 
 TriggerContext::TriggerContext(
     std::unique_ptr<ScriptParameters> script_parameters,
@@ -41,12 +44,14 @@
     bool is_cct,
     bool onboarding_shown,
     bool is_direct_action,
-    const std::string& initial_url)
+    const std::string& initial_url,
+    bool is_in_chrome_triggered)
     : script_parameters_(std::move(script_parameters)),
       experiment_ids_(std::move(experiment_ids)),
       cct_(is_cct),
       onboarding_shown_(onboarding_shown),
       direct_action_(is_direct_action),
+      is_in_chrome_triggered_(is_in_chrome_triggered),
       initial_url_(initial_url) {}
 
 TriggerContext::TriggerContext(std::vector<const TriggerContext*> contexts)
@@ -67,6 +72,7 @@
     cct_ |= context->GetCCT();
     onboarding_shown_ |= context->GetOnboardingShown();
     direct_action_ |= context->GetDirectAction();
+    is_in_chrome_triggered_ |= context->GetInChromeTriggered();
     if (initial_url_.empty()) {
       initial_url_ = context->GetInitialUrl();
     }
@@ -111,4 +117,8 @@
   return direct_action_;
 }
 
+bool TriggerContext::GetInChromeTriggered() const {
+  return is_in_chrome_triggered_;
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/trigger_context.h b/components/autofill_assistant/browser/trigger_context.h
index 69eaed1..e208057 100644
--- a/components/autofill_assistant/browser/trigger_context.h
+++ b/components/autofill_assistant/browser/trigger_context.h
@@ -25,7 +25,8 @@
             bool is_cct,
             bool onboarding_shown,
             bool is_direct_action,
-            const std::string& initial_url);
+            const std::string& initial_url,
+            bool is_in_chrome_triggered);
     Options();
     ~Options();
     std::string experiment_ids;
@@ -33,6 +34,7 @@
     bool onboarding_shown = false;
     bool is_direct_action = false;
     std::string initial_url;
+    bool is_in_chrome_triggered = false;
   };
 
   // Creates an empty trigger context.
@@ -53,7 +55,8 @@
                  bool is_cct,
                  bool onboarding_shown,
                  bool is_direct_action,
-                 const std::string& initial_url);
+                 const std::string& initial_url,
+                 bool is_in_chrome_triggered);
 
   // Creates a trigger context that contains the merged contents of all input
   // instances at the time of calling (does not reference |contexts| after
@@ -92,6 +95,10 @@
   // Returns true if the current action was triggered by a direct action.
   virtual bool GetDirectAction() const;
 
+  // Returns whether this trigger context is coming from an external surface,
+  // i.e., a button or link on a website, or whether this is from within Chrome.
+  virtual bool GetInChromeTriggered() const;
+
  private:
   std::unique_ptr<ScriptParameters> script_parameters_;
 
@@ -102,6 +109,7 @@
   bool cct_ = false;
   bool onboarding_shown_ = false;
   bool direct_action_ = false;
+  bool is_in_chrome_triggered_ = false;
 
   // The initial url at the time of triggering.
   std::string initial_url_;
diff --git a/components/autofill_assistant/browser/trigger_context_unittest.cc b/components/autofill_assistant/browser/trigger_context_unittest.cc
index 616af35..e029318 100644
--- a/components/autofill_assistant/browser/trigger_context_unittest.cc
+++ b/components/autofill_assistant/browser/trigger_context_unittest.cc
@@ -33,7 +33,8 @@
       /* is_cct = */ true,
       /* onboarding_shown = */ true,
       /* is_direct_action = */ true,
-      /* initial_url = */ "https://www.example.com"};
+      /* initial_url = */ "https://www.example.com",
+      /* is_in_chrome_triggered = */ true};
   EXPECT_THAT(context.GetScriptParameters().ToProto(),
               UnorderedElementsAreArray(std::map<std::string, std::string>(
                   {{"key_a", "value_a"}, {"key_b", "value_b"}})));
@@ -42,6 +43,7 @@
   EXPECT_TRUE(context.GetOnboardingShown());
   EXPECT_TRUE(context.GetDirectAction());
   EXPECT_EQ(context.GetInitialUrl(), "https://www.example.com");
+  EXPECT_TRUE(context.GetInChromeTriggered());
 
   context.SetOnboardingShown(false);
   EXPECT_FALSE(context.GetOnboardingShown());
@@ -55,6 +57,7 @@
   EXPECT_FALSE(merged.GetCCT());
   EXPECT_FALSE(merged.GetOnboardingShown());
   EXPECT_FALSE(merged.GetDirectAction());
+  EXPECT_FALSE(merged.GetInChromeTriggered());
 }
 
 TEST(TriggerContextTest, MergeEmptyWithNonEmpty) {
@@ -89,7 +92,8 @@
       /* is_cct = */ true,
       /* onboarding_shown = */ true,
       /* is_direct_action = */ true,
-      /* initial_url = */ "https://www.example.com"};
+      /* initial_url = */ "https://www.example.com",
+      /* is_in_chrome_triggered = */ true};
 
   // Adding empty to make sure empty contexts are properly skipped.
   TriggerContext empty;
@@ -102,6 +106,7 @@
   EXPECT_TRUE(merged.GetOnboardingShown());
   EXPECT_TRUE(merged.GetDirectAction());
   EXPECT_EQ(merged.GetInitialUrl(), "https://www.example.com");
+  EXPECT_TRUE(merged.GetInChromeTriggered());
 }
 
 TEST(TriggerContextTest, HasExperimentId) {
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
index b7c3fb3..db35f42 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.cc
@@ -65,11 +65,13 @@
   deeplink_url_ = deeplink_url;
   trigger_context_ = std::move(trigger_context);
 
-  // Note: do not call ClientContext::Update here. We can only send the version
-  // string in the ClientContext.
+  // Note: do not call ClientContext::Update here. We can only send the
+  // following approved fields:
   ClientContextProto client_context;
   client_context.mutable_chrome()->set_chrome_version(
       version_info::GetProductNameAndVersionForUserAgent());
+  client_context.set_is_in_chrome_triggered(
+      trigger_context_->GetInChromeTriggered());
 
   request_sender_->SendRequest(
       get_trigger_scripts_server_,
diff --git a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
index 2b18d30..7bf7e435 100644
--- a/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
+++ b/components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator_unittest.cc
@@ -221,6 +221,7 @@
         ClientContextProto expected_client_context;
         expected_client_context.mutable_chrome()->set_chrome_version(
             version_info::GetProductNameAndVersionForUserAgent());
+        expected_client_context.set_is_in_chrome_triggered(true);
         EXPECT_THAT(request.client_context(), Eq(expected_client_context));
       });
 
@@ -232,7 +233,8 @@
                           /* is_cct = */ true,
                           /* onboarding_shown = */ true,
                           /* is_direct_action = */ true,
-                          /* initial_url = */ "https://www.example.com"),
+                          /* initial_url = */ "https://www.example.com",
+                          /* is_in_chrome_triggered = */ true),
                       mock_callback_.Get());
 }
 
diff --git a/components/browser_ui/bottomsheet/android/DIR_METADATA b/components/browser_ui/bottomsheet/android/DIR_METADATA
index 1a43921..b87b2836 100644
--- a/components/browser_ui/bottomsheet/android/DIR_METADATA
+++ b/components/browser_ui/bottomsheet/android/DIR_METADATA
@@ -2,6 +2,3 @@
   component: "UI>Browser>Mobile>NavPanel"
 }
 
-team_email: "clank-app-team@google.com"
-
-os: ANDROID
diff --git a/components/browser_ui/http_auth/android/java/res/DIR_METADATA b/components/browser_ui/http_auth/android/java/res/DIR_METADATA
deleted file mode 100644
index 3052711..0000000
--- a/components/browser_ui/http_auth/android/java/res/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-
-os: ANDROID
diff --git a/components/browser_ui/notifications/android/DIR_METADATA b/components/browser_ui/notifications/android/DIR_METADATA
index 55fac6a..0584aa3 100644
--- a/components/browser_ui/notifications/android/DIR_METADATA
+++ b/components/browser_ui/notifications/android/DIR_METADATA
@@ -4,4 +4,3 @@
 
 team_email: "chrome-notifications@google.com"
 
-os: ANDROID
diff --git a/components/browser_ui/share/DIR_METADATA b/components/browser_ui/share/DIR_METADATA
index 3e064095..3593292b 100644
--- a/components/browser_ui/share/DIR_METADATA
+++ b/components/browser_ui/share/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "UI>Browser>Sharing"
 }
 
-os: ANDROID
diff --git a/components/browser_ui/webshare/DIR_METADATA b/components/browser_ui/webshare/DIR_METADATA
index 8875242bb..b5243d7 100644
--- a/components/browser_ui/webshare/DIR_METADATA
+++ b/components/browser_ui/webshare/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>WebShare"
 }
 
-os: ANDROID
diff --git a/components/browser_ui/widget/android/DIR_METADATA b/components/browser_ui/widget/android/DIR_METADATA
deleted file mode 100644
index 496d412..0000000
--- a/components/browser_ui/widget/android/DIR_METADATA
+++ /dev/null
@@ -1,7 +0,0 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
-
-team_email: "clank-app-team@google.com"
-
-os: ANDROID
diff --git a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/DIR_METADATA b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/DIR_METADATA
index 47ead9bc..46d9513 100644
--- a/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/DIR_METADATA
+++ b/components/browser_ui/widget/android/java/src/org/chromium/components/browser_ui/widget/image_tiles/DIR_METADATA
@@ -4,4 +4,3 @@
 
 team_email: "chrome-upboarding@google.com"
 
-os: ANDROID
diff --git a/components/chrome_cleaner/public/proto/DIR_METADATA b/components/chrome_cleaner/public/proto/DIR_METADATA
deleted file mode 100644
index c5f6b73..0000000
--- a/components/chrome_cleaner/public/proto/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Services>Safebrowsing>ChromeCleanup"
-}
-
-team_email: "security-dev@chromium.org"
diff --git a/components/content_settings/common/DIR_METADATA b/components/content_settings/common/DIR_METADATA
deleted file mode 100644
index 9578a5d9..0000000
--- a/components/content_settings/common/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Internals>Permissions>Model"
-}
-team_email: "permissions-dev@chromium.org"
diff --git a/components/crash/android/DIR_METADATA b/components/crash/android/DIR_METADATA
index 7c7d441..7a2580a 100644
--- a/components/crash/android/DIR_METADATA
+++ b/components/crash/android/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "Internals>CrashReporting"
-}
 os: ANDROID
diff --git a/components/crash/content/browser/error_reporting/DIR_METADATA b/components/crash/content/browser/error_reporting/DIR_METADATA
deleted file mode 100644
index 030c855..0000000
--- a/components/crash/content/browser/error_reporting/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>CrashReporting"
-}
diff --git a/components/crash/core/DIR_METADATA b/components/crash/core/DIR_METADATA
deleted file mode 100644
index 030c855..0000000
--- a/components/crash/core/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>CrashReporting"
-}
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/DIR_METADATA b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/DIR_METADATA
deleted file mode 100644
index 2aaf8e2eed..0000000
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Core"
-}
diff --git a/components/exo/buffer_unittest.cc b/components/exo/buffer_unittest.cc
index abdc255..d9ac18d 100644
--- a/components/exo/buffer_unittest.cc
+++ b/components/exo/buffer_unittest.cc
@@ -19,6 +19,7 @@
 #include "ui/aura/env.h"
 #include "ui/compositor/compositor.h"
 #include "ui/compositor/test/in_process_context_provider.h"
+#include "ui/gfx/gpu_fence_handle.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
 namespace exo {
@@ -69,6 +70,7 @@
   // Release buffer.
   std::vector<viz::ReturnedResource> resources;
   resources.emplace_back(resource.id, resource.mailbox_holder.sync_token,
+                         /*release_fence=*/gfx::GpuFenceHandle(),
                          /*count=*/0, /*lost=*/false);
   frame_sink_holder->ReclaimResources(std::move(resources));
 
@@ -109,6 +111,7 @@
   // Release buffer.
   std::vector<viz::ReturnedResource> resources;
   resources.emplace_back(resource.id, gpu::SyncToken(),
+                         /*release_fence=*/gfx::GpuFenceHandle(),
                          /*count=*/0, /*lost=*/true);
   frame_sink_holder->ReclaimResources(std::move(resources));
   base::RunLoop().RunUntilIdle();
@@ -123,6 +126,7 @@
 
   std::vector<viz::ReturnedResource> resources2;
   resources2.emplace_back(new_resource.id, gpu::SyncToken(),
+                          /*release_fence=*/gfx::GpuFenceHandle(),
                           /*count=*/0, /*lost=*/false);
   frame_sink_holder->ReclaimResources(std::move(resources2));
   base::RunLoop().RunUntilIdle();
@@ -252,6 +256,7 @@
     // when frame sink id changes.
     std::vector<viz::ReturnedResource> resources;
     resources.emplace_back(resource.id, resource.mailbox_holder.sync_token,
+                           /*release_fence=*/gfx::GpuFenceHandle(),
                            /*count=*/0, /*lost=*/false);
     frame_sink_holder->ReclaimResources(std::move(resources));
   }
diff --git a/components/exo/shell_surface_util.h b/components/exo/shell_surface_util.h
index 6f42a635..1ca5d25 100644
--- a/components/exo/shell_surface_util.h
+++ b/components/exo/shell_surface_util.h
@@ -46,9 +46,9 @@
                        const absl::optional<std::string>& id);
 const std::string* GetShellStartupId(const aura::Window* window);
 
-// Hides/shows the shelf when fullscreen. If true, shelf is inaccessible
-// (plain fullscreen). If false, shelf auto-hides and can be shown with a
-// mouse gesture (immersive fullscreen).
+// Shows/hides the shelf when fullscreen. If true, titlebar/shelf will show when
+// the mouse moves to the top/bottom of the screen. If false (plain fullscreen),
+// the titlebar and shelf are always hidden.
 void SetShellUseImmersiveForFullscreen(aura::Window* window, bool value);
 
 // Sets the client accessibility ID for the window. The accessibility ID
diff --git a/components/exo/surface.h b/components/exo/surface.h
index aa80467..93161022 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -185,9 +185,9 @@
   // Request that surface should have a specific application ID string.
   void SetApplicationId(const char* application_id);
 
-  // Whether to hide the shelf when fullscreen. If true, shelf is inaccessible
-  // (plain fullscreen). If false, shelf auto-hides and can be shown with a
-  // mouse gesture (immersive fullscreen).
+  // Whether to show/hide the shelf when fullscreen. If true, the titlebar/shelf
+  // will show when the mouse moves to the top/bottom of the screen. If false
+  // (plain fullscreen), the titlebar and shelf are always hidden.
   void SetUseImmersiveForFullscreen(bool value);
 
   // Called to show the snap preview to the right or left, or to hide it.
diff --git a/components/exo/surface_delegate.h b/components/exo/surface_delegate.h
index 165a4f5..61bc97a0 100644
--- a/components/exo/surface_delegate.h
+++ b/components/exo/surface_delegate.h
@@ -44,9 +44,9 @@
   // Called when surface was requested to set a specific application ID label.
   virtual void OnSetApplicationId(const char* application_id) = 0;
 
-  // Whether to hide the shelf when fullscreen. If true, shelf is inaccessible
-  // (plain fullscreen). If false, shelf auto-hides and can be shown with a
-  // mouse gesture (immersive fullscreen).
+  // Whether to show/hide the shelf when fullscreen. If true, the titlebar/shelf
+  // will show when the mouse moves to the top/bottom of the screen. If false
+  // (plain fullscreen), the titlebar and shelf are always hidden.
   virtual void SetUseImmersiveForFullscreen(bool value) = 0;
 
   // Called when the surface's application wants it to be activated.
diff --git a/components/find_in_page/android/DIR_METADATA b/components/find_in_page/android/DIR_METADATA
deleted file mode 100644
index 831a23a2..0000000
--- a/components/find_in_page/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>FindInPage"
-}
diff --git a/components/gcm_driver/android/DIR_METADATA b/components/gcm_driver/android/DIR_METADATA
deleted file mode 100644
index 356995f..0000000
--- a/components/gcm_driver/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Services>CloudMessaging"
-}
diff --git a/components/guest_view/common/DIR_METADATA b/components/guest_view/common/DIR_METADATA
deleted file mode 100644
index 22d44120c..0000000
--- a/components/guest_view/common/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Apps>BrowserTag"
-}
diff --git a/components/history/core/browser/top_sites_impl.cc b/components/history/core/browser/top_sites_impl.cc
index 587d9a9..9db45ba 100644
--- a/components/history/core/browser/top_sites_impl.cc
+++ b/components/history/core/browser/top_sites_impl.cc
@@ -155,7 +155,8 @@
   {
     DictionaryPrefUpdate update(pref_service_, kBlockedUrlsPrefsKey);
     base::DictionaryValue* blocked_urls = update.Get();
-    blocked_urls->SetWithoutPathExpansion(GetURLHash(url), std::move(dummy));
+    blocked_urls->SetKey(GetURLHash(url),
+                         base::Value::FromUniquePtrValue(std::move(dummy)));
   }
 
   ResetThreadSafeCache();
diff --git a/components/media_router/browser/android/DIR_METADATA b/components/media_router/browser/android/DIR_METADATA
deleted file mode 100644
index 1d3a283d..0000000
--- a/components/media_router/browser/android/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Internals>Cast"
-}
-team_email: "media-dev@chromium.org"
diff --git a/components/metrics/structured/DIR_METADATA b/components/metrics/structured/DIR_METADATA
deleted file mode 100644
index 540f41c..0000000
--- a/components/metrics/structured/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Metrics"
-}
diff --git a/components/metrics/system_session_analyzer/DIR_METADATA b/components/metrics/system_session_analyzer/DIR_METADATA
deleted file mode 100644
index 540f41c..0000000
--- a/components/metrics/system_session_analyzer/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Metrics"
-}
diff --git a/components/nacl/loader/nonsfi/DIR_METADATA b/components/nacl/loader/nonsfi/DIR_METADATA
deleted file mode 100644
index 096cb71..0000000
--- a/components/nacl/loader/nonsfi/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>NaCl"
-}
diff --git a/components/nacl/loader/sandbox_linux/DIR_METADATA b/components/nacl/loader/sandbox_linux/DIR_METADATA
deleted file mode 100644
index 096cb71..0000000
--- a/components/nacl/loader/sandbox_linux/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>NaCl"
-}
diff --git a/components/omnibox/browser/android/DIR_METADATA b/components/omnibox/browser/android/DIR_METADATA
index ad71892..8cf9f01 100644
--- a/components/omnibox/browser/android/DIR_METADATA
+++ b/components/omnibox/browser/android/DIR_METADATA
@@ -1,4 +1 @@
-monorail {
-  component: "UI>Browser>Omnibox"
-}
 team_email: "chrome-android-omnibox-team@google.com"
diff --git a/components/page_info/android/DIR_METADATA b/components/page_info/android/DIR_METADATA
deleted file mode 100644
index 0c8becc5..0000000
--- a/components/page_info/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Bubbles>PageInfo"
-}
diff --git a/components/page_load_metrics/browser/DIR_METADATA b/components/page_load_metrics/browser/DIR_METADATA
deleted file mode 100644
index 9c0622f..0000000
--- a/components/page_load_metrics/browser/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Speed>Metrics"
-}
diff --git a/components/page_load_metrics/browser/observers/core/DIR_METADATA b/components/page_load_metrics/browser/observers/core/DIR_METADATA
deleted file mode 100644
index 9c0622f..0000000
--- a/components/page_load_metrics/browser/observers/core/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Speed>Metrics"
-}
diff --git a/components/password_manager/core/browser/android_affiliation/DIR_METADATA b/components/password_manager/core/browser/android_affiliation/DIR_METADATA
deleted file mode 100644
index 43d76b8..0000000
--- a/components/password_manager/core/browser/android_affiliation/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Passwords"
-}
diff --git a/components/password_manager/core/browser/export/DIR_METADATA b/components/password_manager/core/browser/export/DIR_METADATA
deleted file mode 100644
index 14f1f46..0000000
--- a/components/password_manager/core/browser/export/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "UI>Browser>Passwords"
-}
-team_email: "chromium-dev@chromium.org"
diff --git a/components/pdf/renderer/DIR_METADATA b/components/pdf/renderer/DIR_METADATA
deleted file mode 100644
index 507a6ca..0000000
--- a/components/pdf/renderer/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Plugins>PDF"
-}
diff --git a/components/performance_manager/v8_memory/web_memory_aggregator.cc b/components/performance_manager/v8_memory/web_memory_aggregator.cc
index f2c23c32a..522c9fa2 100644
--- a/components/performance_manager/v8_memory/web_memory_aggregator.cc
+++ b/components/performance_manager/v8_memory/web_memory_aggregator.cc
@@ -438,7 +438,10 @@
         return true;
       },
       browsing_instance_id, &bytes_used, &total_bytes_used));
-  return static_cast<double>(bytes_used) / total_bytes_used;
+  DCHECK_LE(bytes_used, total_bytes_used);
+  return total_bytes_used == 0
+             ? 1
+             : static_cast<double>(bytes_used) / total_bytes_used;
 }
 
 }  // anonymous namespace
diff --git a/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc b/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
index b700f6d..a8aad6a 100644
--- a/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
+++ b/components/performance_manager/v8_memory/web_memory_aggregator_unittest.cc
@@ -627,6 +627,26 @@
   }
 }
 
+TEST_F(WebMemoryAggregatorTest, BlinkMemoryWithoutFrameBytes) {
+  FrameNodeImpl* a_com = AddFrameNode("https://a.com/", absl::nullopt);
+  SetBlinkMemory(Bytes{1000});
+  {
+    WebMemoryAggregator aggregator(a_com);
+    auto expected_result =
+        CreateExpectedMemoryMeasurement({ExpectedMemoryBreakdown(
+            absl::nullopt, AttributionScope::kWindow, "https://a.com/")});
+    expected_result->blink_memory = mojom::WebMemoryUsage::New();
+    expected_result->blink_memory->bytes = 1000;
+    expected_result->shared_memory = mojom::WebMemoryUsage::New();
+    expected_result->shared_memory->bytes = 0;
+    expected_result->detached_memory = mojom::WebMemoryUsage::New();
+    expected_result->detached_memory->bytes = 0;
+    auto result = aggregator.AggregateMeasureMemoryResult();
+    EXPECT_EQ(NormalizeMeasurement(result),
+              NormalizeMeasurement(expected_result));
+  }
+}
+
 TEST_F(WebMemoryAggregatorTest, BlinkMemoryMultipleBrowsingInstances) {
   FrameNodeImpl* a_com = AddFrameNode("https://a.com/", Bytes{10});
   AddCrossBrowsingInstanceFrameNode("https://b.com/", Bytes{30});
diff --git a/components/permissions/contexts/DIR_METADATA b/components/permissions/contexts/DIR_METADATA
deleted file mode 100644
index b1e8e6f3..0000000
--- a/components/permissions/contexts/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Internals>Permissions"
-}
-
-team_email: "permissions-dev@chromium.org"
diff --git a/components/policy/core/common/plist_writer_unittest.cc b/components/policy/core/common/plist_writer_unittest.cc
index 0d89d0a..51e0814 100644
--- a/components/policy/core/common/plist_writer_unittest.cc
+++ b/components/policy/core/common/plist_writer_unittest.cc
@@ -115,7 +115,8 @@
   std::unique_ptr<base::DictionaryValue> period_dict2(
       new base::DictionaryValue());
   period_dict2->SetKey("g.h.i.j", base::Value(1));
-  period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
+  period_dict.SetKey("d.e.f",
+                     base::Value::FromUniquePtrValue(std::move(period_dict2)));
   EXPECT_TRUE(PlistWrite(period_dict, &output_plist));
   EXPECT_EQ(base::StrCat({header_,       " <dict>",
                           PLIST_NEWLINE, "  <key>a.b</key>",
diff --git a/components/policy/resources/DIR_METADATA b/components/policy/resources/DIR_METADATA
deleted file mode 100644
index 3ecb477..0000000
--- a/components/policy/resources/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Enterprise"
-}
diff --git a/components/policy/tools/DIR_METADATA b/components/policy/tools/DIR_METADATA
deleted file mode 100644
index 3ecb477..0000000
--- a/components/policy/tools/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Enterprise"
-}
diff --git a/components/prefs/android/DIR_METADATA b/components/prefs/android/DIR_METADATA
index 830f167d..1744a1f 100644
--- a/components/prefs/android/DIR_METADATA
+++ b/components/prefs/android/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Preferences"
-}
 
 os: ANDROID
diff --git a/components/printing/browser/DIR_METADATA b/components/printing/browser/DIR_METADATA
deleted file mode 100644
index c6bf1f0..0000000
--- a/components/printing/browser/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Printing"
-}
diff --git a/components/printing/common/DIR_METADATA b/components/printing/common/DIR_METADATA
deleted file mode 100644
index c6bf1f0..0000000
--- a/components/printing/common/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Printing"
-}
diff --git a/components/printing/resources/DIR_METADATA b/components/printing/resources/DIR_METADATA
deleted file mode 100644
index c6bf1f0..0000000
--- a/components/printing/resources/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Printing"
-}
diff --git a/components/safe_browsing/android/DIR_METADATA b/components/safe_browsing/android/DIR_METADATA
deleted file mode 100644
index 578f3dfc..0000000
--- a/components/safe_browsing/android/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Services>Safebrowsing"
-}
-
-team_email: "safebrowsing@chromium.org"
diff --git a/components/safe_browsing/content/browser/client_side_detection_host.cc b/components/safe_browsing/content/browser/client_side_detection_host.cc
index 7623544b..ac0891b 100644
--- a/components/safe_browsing/content/browser/client_side_detection_host.cc
+++ b/components/safe_browsing/content/browser/client_side_detection_host.cc
@@ -314,6 +314,7 @@
       is_off_the_record_(is_off_the_record),
       account_signed_in_callback_(account_signed_in_callback) {
   DCHECK(tab);
+  DCHECK(pref_service);
   // Note: csd_service_ and sb_service will be nullptr here in testing.
   csd_service_ = delegate_->GetClientSideDetectionService();
 
@@ -553,7 +554,8 @@
   // primary user account is signed in.
   return base::FeatureList::IsEnabled(kClientSideDetectionWithToken) &&
          IsEnhancedProtectionEnabled(*pref_service_) &&
-         std::move(account_signed_in_callback_).Run();
+         !account_signed_in_callback_.is_null() &&
+         account_signed_in_callback_.Run();
 }
 
 void ClientSideDetectionHost::SendRequest(
diff --git a/components/safe_browsing/content/password_protection/DIR_METADATA b/components/safe_browsing/content/password_protection/DIR_METADATA
deleted file mode 100644
index 578f3dfc..0000000
--- a/components/safe_browsing/content/password_protection/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Services>Safebrowsing"
-}
-
-team_email: "safebrowsing@chromium.org"
diff --git a/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
index 0febb7a..6fd76b2 100644
--- a/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/content/password_protection/password_protection_service_unittest.cc
@@ -464,14 +464,16 @@
 
     std::unique_ptr<base::DictionaryValue> invalid_cache_expression_entry =
         std::make_unique<base::DictionaryValue>();
-    invalid_cache_expression_entry->SetWithoutPathExpansion(
-        "invalid_cache_expression", std::move(invalid_verdict_entry));
-    verdict_dictionary->SetWithoutPathExpansion(
+    invalid_cache_expression_entry->SetKey(
+        "invalid_cache_expression",
+        base::Value::FromUniquePtrValue(std::move(invalid_verdict_entry)));
+    verdict_dictionary->SetKey(
         base::NumberToString(static_cast<std::underlying_type_t<PasswordType>>(
             password_protection_service_
                 ->ConvertReusedPasswordAccountTypeToPasswordType(
                     password_type))),
-        std::move(invalid_cache_expression_entry));
+        base::Value::FromUniquePtrValue(
+            std::move(invalid_cache_expression_entry)));
     content_setting_map_->SetWebsiteSettingDefaultScope(
         invalid_hostname, GURL(), ContentSettingsType::PASSWORD_PROTECTION,
         std::move(verdict_dictionary));
diff --git a/components/safe_browsing/core/password_protection/DIR_METADATA b/components/safe_browsing/core/password_protection/DIR_METADATA
deleted file mode 100644
index ee2d9cf5..0000000
--- a/components/safe_browsing/core/password_protection/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail: {
-  component: "Services>Safebrowsing"
-}
-team_email: "safebrowsing@chromium.org"
diff --git a/components/safe_browsing/core/realtime/DIR_METADATA b/components/safe_browsing/core/realtime/DIR_METADATA
deleted file mode 100644
index 578f3dfc..0000000
--- a/components/safe_browsing/core/realtime/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Services>Safebrowsing"
-}
-
-team_email: "safebrowsing@chromium.org"
diff --git a/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc b/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
index 729650f..cd698b5 100644
--- a/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
+++ b/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
@@ -35,8 +35,8 @@
     classification_dict->SetBoolean("pornography", is_porn);
   auto classifications_list = std::make_unique<base::ListValue>();
   classifications_list->Append(std::move(classification_dict));
-  dict.SetWithoutPathExpansion("classifications",
-                               std::move(classifications_list));
+  dict.SetKey("classifications",
+              base::Value::FromUniquePtrValue(std::move(classifications_list)));
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
diff --git a/components/safe_search_api/stub_url_checker.cc b/components/safe_search_api/stub_url_checker.cc
index b32462d..bdd2cc28 100644
--- a/components/safe_search_api/stub_url_checker.cc
+++ b/components/safe_search_api/stub_url_checker.cc
@@ -29,8 +29,8 @@
     classification_dict->SetBoolean("pornography", is_porn);
   auto classifications_list = std::make_unique<base::ListValue>();
   classifications_list->Append(std::move(classification_dict));
-  dict.SetWithoutPathExpansion("classifications",
-                               std::move(classifications_list));
+  dict.SetKey("classifications",
+              base::Value::FromUniquePtrValue(std::move(classifications_list)));
   std::string result;
   base::JSONWriter::Write(dict, &result);
   return result;
diff --git a/components/search_engines/android/DIR_METADATA b/components/search_engines/android/DIR_METADATA
deleted file mode 100644
index 4bbdcae..0000000
--- a/components/search_engines/android/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>Search"
-}
diff --git a/components/services/storage/dom_storage/DIR_METADATA b/components/services/storage/dom_storage/DIR_METADATA
index f5d8083..69f4bfe 100644
--- a/components/services/storage/dom_storage/DIR_METADATA
+++ b/components/services/storage/dom_storage/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Storage>DOMStorage"
 }
 
-team_email: "storage-dev@chromium.org"
diff --git a/components/services/storage/indexed_db/DIR_METADATA b/components/services/storage/indexed_db/DIR_METADATA
index af99a94..0d8be5e 100644
--- a/components/services/storage/indexed_db/DIR_METADATA
+++ b/components/services/storage/indexed_db/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Storage>IndexedDB"
 }
 
-team_email: "storage-dev@chromium.org"
diff --git a/components/session_manager/core/DIR_METADATA b/components/session_manager/core/DIR_METADATA
deleted file mode 100644
index d08126ac..0000000
--- a/components/session_manager/core/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Shell"
-}
diff --git a/components/signin/ios/DIR_METADATA b/components/signin/ios/DIR_METADATA
deleted file mode 100644
index 5fad689..0000000
--- a/components/signin/ios/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Services>SignIn"
-}
diff --git a/components/signin/public/android/DIR_METADATA b/components/signin/public/android/DIR_METADATA
deleted file mode 100644
index 4735e25f..0000000
--- a/components/signin/public/android/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Services>SignIn"
-}
-
-team_email: "chrome-signin@chromium.org"
diff --git a/components/url_formatter/tools/DIR_METADATA b/components/url_formatter/tools/DIR_METADATA
deleted file mode 100644
index f5b2b44..0000000
--- a/components/url_formatter/tools/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Security>UrlFormatting"
-}
diff --git a/components/url_matcher/url_matcher_factory_unittest.cc b/components/url_matcher/url_matcher_factory_unittest.cc
index df62aff..31301e2 100644
--- a/components/url_matcher/url_matcher_factory_unittest.cc
+++ b/components/url_matcher/url_matcher_factory_unittest.cc
@@ -237,7 +237,8 @@
   if (use_list_of_strings_) {
     auto list = std::make_unique<base::ListValue>();
     list->AppendString(value);
-    condition.SetWithoutPathExpansion(condition_key_, std::move(list));
+    condition.SetKey(condition_key_,
+                     base::Value::FromUniquePtrValue(std::move(list)));
   } else {
     condition.SetKey(condition_key_, base::Value(value));
   }
diff --git a/components/viz/common/resources/returned_resource.cc b/components/viz/common/resources/returned_resource.cc
index 6582eb2..10f1a7c 100644
--- a/components/viz/common/resources/returned_resource.cc
+++ b/components/viz/common/resources/returned_resource.cc
@@ -3,14 +3,20 @@
 // found in the LICENSE file.
 
 #include "components/viz/common/resources/returned_resource.h"
+#include "ui/gfx/gpu_fence_handle.h"
 
 namespace viz {
 
 ReturnedResource::ReturnedResource(ResourceId id,
                                    gpu::SyncToken sync_token,
+                                   gfx::GpuFenceHandle release_fence,
                                    int count,
                                    bool lost)
-    : id(id), sync_token(sync_token), count(count), lost(lost) {}
+    : id(id),
+      sync_token(sync_token),
+      release_fence(std::move(release_fence)),
+      count(count),
+      lost(lost) {}
 
 ReturnedResource::ReturnedResource() = default;
 
diff --git a/components/viz/common/resources/returned_resource.h b/components/viz/common/resources/returned_resource.h
index 1758e4c1..459e9d9 100644
--- a/components/viz/common/resources/returned_resource.h
+++ b/components/viz/common/resources/returned_resource.h
@@ -8,6 +8,7 @@
 #include "components/viz/common/resources/resource_id.h"
 #include "components/viz/common/viz_common_export.h"
 #include "gpu/command_buffer/common/sync_token.h"
+#include "ui/gfx/gpu_fence_handle.h"
 
 namespace viz {
 
@@ -17,6 +18,7 @@
 struct VIZ_COMMON_EXPORT ReturnedResource {
   ReturnedResource(ResourceId id,
                    gpu::SyncToken sync_token,
+                   gfx::GpuFenceHandle release_fence,
                    int count,
                    bool lost);
 
@@ -28,15 +30,6 @@
   ReturnedResource(const ReturnedResource& other) = delete;
   ReturnedResource& operator=(const ReturnedResource& other) = delete;
 
-  bool operator==(const ReturnedResource& other) const {
-    return id == other.id && sync_token == other.sync_token &&
-           count == other.count && lost == other.lost;
-  }
-
-  bool operator!=(const ReturnedResource& other) const {
-    return !(*this == other);
-  }
-
   // |id| is an identifier generated by the child compositor that uniquely
   // identifies a resource. This is the same ID space as TransferableResource.
   ResourceId id = kInvalidResourceId;
@@ -48,6 +41,11 @@
   // are executed before commands submitted by the child.
   gpu::SyncToken sync_token;
 
+  // Release fence for this resource. If this is a valid fence then the client
+  // may use it to wait if they need to perform external operations
+  // (e.g. CPU operations) on this resource.
+  gfx::GpuFenceHandle release_fence;
+
   // |count| is a reference count for this resource. A resource may be used
   // by mulitple compositor frames submitted to the parent compositor. |count|
   // is the number of references being returned back to the child compositor.
diff --git a/components/viz/service/display/direct_renderer.h b/components/viz/service/display/direct_renderer.h
index 3625ec4..22a9122 100644
--- a/components/viz/service/display/direct_renderer.h
+++ b/components/viz/service/display/direct_renderer.h
@@ -98,7 +98,8 @@
   };
   virtual void SwapBuffers(SwapFrameData swap_frame_data) = 0;
   virtual void SwapBuffersSkipped() {}
-  virtual void SwapBuffersComplete() {}
+  virtual void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {}
+  virtual void BuffersPresented() {}
   virtual void DidReceiveTextureInUseResponses(
       const gpu::TextureInUseResponses& responses) {}
   virtual void DidReceiveReleasedOverlays(
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index f1a4eaf..f371b4f 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -969,7 +969,7 @@
   if (overlay_processor_)
     overlay_processor_->OverlayPresentationComplete();
   if (renderer_)
-    renderer_->SwapBuffersComplete();
+    renderer_->SwapBuffersComplete(std::move(release_fence));
 
   // It's possible to receive multiple calls to DidReceiveSwapBuffersAck()
   // before DidReceivePresentationFeedback(). Ensure that we're not setting
@@ -1044,6 +1044,9 @@
 
 void Display::DidReceivePresentationFeedback(
     const gfx::PresentationFeedback& feedback) {
+  if (renderer_)
+    renderer_->BuffersPresented();
+
   if (pending_presentation_group_timings_.empty()) {
     DLOG(ERROR) << "Received unexpected PresentationFeedback";
     return;
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc
index a4e088f9..d0738b30 100644
--- a/components/viz/service/display/display_resource_provider.cc
+++ b/components/viz/service/display/display_resource_provider.cc
@@ -456,6 +456,18 @@
   return *this;
 }
 
+void DisplayResourceProvider::ScopedReadLockSharedImage::SetReleaseFence(
+    gfx::GpuFenceHandle release_fence) {
+  DCHECK(resource_);
+  resource_->release_fence = std::move(release_fence);
+}
+
+bool DisplayResourceProvider::ScopedReadLockSharedImage::HasReadLockFence()
+    const {
+  DCHECK(resource_);
+  return resource_->transferable.read_lock_fences_enabled;
+}
+
 void DisplayResourceProvider::ScopedReadLockSharedImage::Reset() {
   if (!resource_provider_)
     return;
diff --git a/components/viz/service/display/display_resource_provider.h b/components/viz/service/display/display_resource_provider.h
index 5f8e7f30..c9cea0d 100644
--- a/components/viz/service/display/display_resource_provider.h
+++ b/components/viz/service/display/display_resource_provider.h
@@ -121,6 +121,13 @@
       return resource_->sync_token();
     }
 
+    // Sets the given |release_fence| onto this resource.
+    // This is propagated to ReturnedResource when the resource is freed.
+    void SetReleaseFence(gfx::GpuFenceHandle release_fence);
+
+    // Returns true iff this resource has a read lock fence set.
+    bool HasReadLockFence() const;
+
    protected:
     ChildResource* resource() { return resource_; }
 
@@ -330,6 +337,10 @@
     // to avoid map lookups further down the pipeline.
     std::unique_ptr<ExternalUseClient::ImageContext> image_context;
 
+    // A release fence to propagate to ReturnedResource so clients may
+    // use it.
+    gfx::GpuFenceHandle release_fence;
+
    private:
     // Tracks if a sync token needs to be waited on before using the resource.
     SynchronizationState synchronization_state_;
diff --git a/components/viz/service/display/display_resource_provider_gl.cc b/components/viz/service/display/display_resource_provider_gl.cc
index c978378..b9ad396 100644
--- a/components/viz/service/display/display_resource_provider_gl.cc
+++ b/components/viz/service/display/display_resource_provider_gl.cc
@@ -223,6 +223,7 @@
     }
 
     to_return.emplace_back(child_id, resource.sync_token(),
+                           std::move(resource.release_fence),
                            resource.imported_count, is_lost);
     auto& returned = to_return.back();
 
diff --git a/components/viz/service/display/display_resource_provider_null.cc b/components/viz/service/display/display_resource_provider_null.cc
index 733970f..559bf31 100644
--- a/components/viz/service/display/display_resource_provider_null.cc
+++ b/components/viz/service/display/display_resource_provider_null.cc
@@ -35,6 +35,7 @@
     DCHECK_EQ(can_delete, CanDeleteNowResult::kYes);
 
     to_return.emplace_back(child_id, resource.sync_token(),
+                           std::move(resource.release_fence),
                            resource.imported_count, /*is_lost=*/false);
 
     child_info.child_to_parent_map.erase(child_id);
diff --git a/components/viz/service/display/display_resource_provider_skia.cc b/components/viz/service/display/display_resource_provider_skia.cc
index 78e74bb..fb0e591 100644
--- a/components/viz/service/display/display_resource_provider_skia.cc
+++ b/components/viz/service/display/display_resource_provider_skia.cc
@@ -85,6 +85,7 @@
     const bool is_lost = can_delete == CanDeleteNowResult::kYesButLoseResource;
 
     to_return.emplace_back(child_id, resource.sync_token(),
+                           std::move(resource.release_fence),
                            resource.imported_count, is_lost);
     auto& returned = to_return.back();
 
diff --git a/components/viz/service/display/display_resource_provider_software.cc b/components/viz/service/display/display_resource_provider_software.cc
index 31a6200..78fda8a7 100644
--- a/components/viz/service/display/display_resource_provider_software.cc
+++ b/components/viz/service/display/display_resource_provider_software.cc
@@ -92,6 +92,7 @@
     const bool is_lost = can_delete == CanDeleteNowResult::kYesButLoseResource;
 
     to_return.emplace_back(child_id, resource.sync_token(),
+                           std::move(resource.release_fence),
                            resource.imported_count, is_lost);
 
     child_info.child_to_parent_map.erase(child_id);
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index f2032b6f0..80cafcc0 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -78,6 +78,7 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/gpu_fence_handle.h"
 #include "ui/gfx/rrect_f.h"
 #include "ui/gfx/skia_util.h"
 
@@ -3455,7 +3456,8 @@
   }
 }
 
-void GLRenderer::SwapBuffersComplete() {
+void GLRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
+  DCHECK(release_fence.is_null());
   if (settings_->release_overlay_resources_after_gpu_query) {
     // Once a resource has been swap-ACKed, send a query to the GPU process to
     // ask if the resource is no longer being consumed by the system compositor.
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 7edda1a..eaa4871b 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -34,6 +34,7 @@
 #include "components/viz/service/display/texture_deleter.h"
 #include "components/viz/service/viz_service_export.h"
 #include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/gpu_fence_handle.h"
 #include "ui/latency/latency_info.h"
 
 #if defined(OS_APPLE)
@@ -85,7 +86,7 @@
 
   void SwapBuffers(SwapFrameData swap_frame_data) override;
   void SwapBuffersSkipped() override;
-  void SwapBuffersComplete() override;
+  void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) override;
 
   void DidReceiveTextureInUseResponses(
       const gpu::TextureInUseResponses& responses) override;
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 3495ba8..60c460a 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -4065,7 +4065,7 @@
 
     DrawFrame(&renderer(), viewport_size);
     renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-    renderer().SwapBuffersComplete();
+    renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
     Mock::VerifyAndClearExpectations(&gl());
   }
 
@@ -4287,7 +4287,7 @@
 
   // The texture will be checked to verify if it is free yet.
   EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
-  renderer().SwapBuffersComplete();
+  renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   Mock::VerifyAndClearExpectations(&gl());
 
   // Frame number 2. We change the size of the child RenderPass to be smaller
@@ -4333,7 +4333,7 @@
 
   // There are now 2 textures to check if they are free.
   EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
-  renderer().SwapBuffersComplete();
+  renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   Mock::VerifyAndClearExpectations(&gl());
 
   // The first (256x256) texture is returned to the GLRenderer.
@@ -4442,7 +4442,7 @@
 
   // The texture will be checked to verify if it is free yet.
   EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
-  renderer().SwapBuffersComplete();
+  renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   Mock::VerifyAndClearExpectations(&gl());
 
   // Frame number 2. We change the size of the child RenderPass to be much
@@ -4486,7 +4486,7 @@
 
   // There are now 2 textures to check if they are free.
   EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
-  renderer().SwapBuffersComplete();
+  renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   Mock::VerifyAndClearExpectations(&gl());
 
   // The first (256x256) texture is returned to the GLRenderer.
@@ -4620,7 +4620,7 @@
 
   // There are 2 textures to check if they are free.
   EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
-  renderer().SwapBuffersComplete();
+  renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   Mock::VerifyAndClearExpectations(&gl());
 
   // Both textures get returned and the 2nd one can be reused.
@@ -4720,7 +4720,7 @@
 
     // All sent textures will be checked to verify if they are free yet.
     EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 1, _));
-    renderer().SwapBuffersComplete();
+    renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
     Mock::VerifyAndClearExpectations(&gl());
   }
 
@@ -4789,7 +4789,7 @@
     // also 1 outstanding texture to check for that wasn't returned yet from the
     // above loop.
     EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 2, _));
-    renderer().SwapBuffersComplete();
+    renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
     Mock::VerifyAndClearExpectations(&gl());
   }
 }
@@ -4849,7 +4849,7 @@
 
     // All sent textures will be checked to verify if they are free yet.
     EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 1, _));
-    renderer().SwapBuffersComplete();
+    renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
     Mock::VerifyAndClearExpectations(&gl());
   }
 
@@ -4882,7 +4882,7 @@
 
     // There's just 1 outstanding RenderPass texture to query for.
     EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
-    renderer().SwapBuffersComplete();
+    renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
     Mock::VerifyAndClearExpectations(&gl());
   }
 
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 8c19dfd0..61dd56f 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -3450,10 +3450,12 @@
   }
   void SwapBuffers() {
     renderer_->SwapBuffers({});
-    renderer_->SwapBuffersComplete();
+    renderer_->SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
   }
   void SwapBuffersWithoutComplete() { renderer_->SwapBuffers({}); }
-  void SwapBuffersComplete() { renderer_->SwapBuffersComplete(); }
+  void SwapBuffersComplete() {
+    renderer_->SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
+  }
   void ReturnResourceInUseQuery(ResourceId id) {
     DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(),
                                                      id);
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 478a04ad..946c981 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -810,7 +810,14 @@
   FlushOutputSurface();
 }
 
-void SkiaRenderer::SwapBuffersComplete() {
+void SkiaRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
+  if (!release_fence.is_null()) {
+    // Set release fences for returning for last frame overlay resources.
+    for (auto& lock : committed_overlay_locks_) {
+      lock.SetReleaseFence(release_fence.Clone());
+    }
+  }
+
   // Right now, only macOS needs to return mailboxes of released overlays, so
   // we should not release |committed_overlay_locks_| here. The resources in it
   // will be released by DidReceiveReleasedOverlays() later.
@@ -820,11 +827,31 @@
   }
 #endif  // defined(OS_APPLE)
 
+  // Find all locks that have a read-lock fence associated with them.
+  // If we have a release fence, it's not safe to release them here.
+  // Release them later in BuffersPresented.
+  auto& read_lock_release_fence_overlay_locks =
+      read_lock_release_fence_overlay_locks_.emplace_back();
+  if (!release_fence.is_null()) {
+    auto read_lock_iter = std::partition(
+        committed_overlay_locks_.begin(), committed_overlay_locks_.end(),
+        [](auto& lock) { return !lock.HasReadLockFence(); });
+    read_lock_release_fence_overlay_locks.insert(
+        read_lock_release_fence_overlay_locks.end(),
+        std::make_move_iterator(read_lock_iter),
+        std::make_move_iterator(committed_overlay_locks_.end()));
+  }
+
   committed_overlay_locks_.clear();
   std::swap(committed_overlay_locks_, pending_overlay_locks_.front());
   pending_overlay_locks_.pop_front();
 }
 
+void SkiaRenderer::BuffersPresented() {
+  DCHECK(!read_lock_release_fence_overlay_locks_.empty());
+  read_lock_release_fence_overlay_locks_.pop_front();
+}
+
 void SkiaRenderer::DidReceiveReleasedOverlays(
     const std::vector<gpu::Mailbox>& released_overlays) {
   // This method is only called on macOS right now.
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index da00b57..acb51b7 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -51,7 +51,8 @@
 
   void SwapBuffers(SwapFrameData swap_frame_data) override;
   void SwapBuffersSkipped() override;
-  void SwapBuffersComplete() override;
+  void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) override;
+  void BuffersPresented() override;
   void DidReceiveReleasedOverlays(
       const std::vector<gpu::Mailbox>& released_overlays) override;
 
@@ -324,6 +325,11 @@
   std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>
       committed_overlay_locks_;
 
+  // Locks for overlays that have release fences and read lock fences.
+  base::circular_deque<
+      std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>>
+      read_lock_release_fence_overlay_locks_;
+
 #if defined(OS_APPLE)
   class ScopedReadLockComparator {
    public:
diff --git a/components/viz/test/test_gles2_interface.cc b/components/viz/test/test_gles2_interface.cc
index 8220e9d..d46a3e4 100644
--- a/components/viz/test/test_gles2_interface.cc
+++ b/components/viz/test/test_gles2_interface.cc
@@ -5,6 +5,7 @@
 #include "components/viz/test/test_gles2_interface.h"
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 350c0d4..7f32ce81 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -2710,6 +2710,7 @@
       "//third_party/icu",
       "//ui/accessibility:ax_assistant",
       "//ui/accessibility/mojom",
+      "//ui/accessibility/mojom:ax_assistant_mojom",
       "//ui/android",
       "//ui/compositor",
       "//url:gurl_android",
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 4ed237d..32c322ac 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -3633,6 +3633,59 @@
   ExpectRestored(FROM_HERE);
 }
 
+// Navigates from page A -> page B -> page C -> page B -> page C. Page B becomes
+// ineligible for bfcache in pagehide handler, so Page A stays in bfcache
+// without being evicted even after the navigation to Page C.
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestShouldConsiderPagehideForEligibility,
+    PagehideMakesPageIneligibleForBackForwardCacheAndNotCountedInCacheSize) {
+  ASSERT_TRUE(CreateHttpsServer()->Start());
+  GURL url_a(https_server()->GetURL("a.com", "/title1.html"));
+  GURL url_b(https_server()->GetURL(
+      "b.com", "/back_forward_cache/page_with_broadcastchannel.html"));
+  GURL url_c(https_server()->GetURL("c.com", "/title1.html"));
+
+  // 1) Navigate to a.com.
+  EXPECT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+
+  // 2) Navigate to b.com.
+  EXPECT_TRUE(NavigateToURL(shell(), url_b));
+  RenderFrameHostImpl* rfh_b = current_frame_host();
+  RenderFrameDeletedObserver deleted_observer_rfh_b(rfh_b);
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+  // Acquire broadcast in pagehide. Now b.com is not eligible for bfcache.
+  EXPECT_TRUE(
+      ExecJs(rfh_b, "setShouldAcquireBroadcastChannelInPageHide(true);"));
+
+  // 3) Navigate to c.com.
+  EXPECT_TRUE(NavigateToURL(shell(), url_c));
+  // RenderFrameHostImpl* rfh_c = current_frame_host();
+  // Since the b.com is not eligible for bfcache, |rfh_a| should stay in
+  // bfcache.
+  deleted_observer_rfh_b.WaitUntilDeleted();
+  EXPECT_TRUE(rfh_a->IsInBackForwardCache());
+
+  // 4) Navigate back to b.com.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      {blink::scheduler::WebSchedulerTrackedFeature::kBroadcastChannel}, {}, {},
+      FROM_HERE);
+  RenderFrameHostImpl* rfh_b_2 = current_frame_host();
+  // Do not acquire broadcast channel. Now b.com is eligible for bfcache.
+  EXPECT_TRUE(
+      ExecJs(rfh_b_2, "setShouldAcquireBroadcastChannelInPageHide(false);"));
+
+  // 5) Navigate forward to c.com.
+  web_contents()->GetController().GoForward();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectRestored(FROM_HERE);
+  // b.com was eligible for bfcache and should stay in bfcache.
+  EXPECT_TRUE(rfh_b_2->IsInBackForwardCache());
+}
+
 // Track the events dispatched when a page is deemed ineligible for back-forward
 // cache after we've dispatched the 'pagehide' event with persisted set to true.
 IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest,
diff --git a/content/browser/devtools/protocol/DIR_METADATA b/content/browser/devtools/protocol/DIR_METADATA
deleted file mode 100644
index d78c650..0000000
--- a/content/browser/devtools/protocol/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>DevTools"
-}
diff --git a/content/browser/loader/navigation_early_hints_manager.cc b/content/browser/loader/navigation_early_hints_manager.cc
index de1cdcf..4bca62ac 100644
--- a/content/browser/loader/navigation_early_hints_manager.cc
+++ b/content/browser/loader/navigation_early_hints_manager.cc
@@ -284,6 +284,10 @@
   return was_preload_link_header_received_;
 }
 
+bool NavigationEarlyHintsManager::HasInflightPreloads() const {
+  return inflight_preloads_.size() > 0;
+}
+
 void NavigationEarlyHintsManager::WaitForPreloadsFinishedForTesting(
     base::OnceCallback<void(PreloadedResources)> callback) {
   DCHECK(!preloads_completion_callback_for_testing_);
@@ -306,6 +310,10 @@
   if (!base::FeatureList::IsEnabled(features::kEarlyHintsPreloadForNavigation))
     return;
 
+  if (!link->href.SchemeIsHTTPOrHTTPS()) {
+    return;
+  }
+
   if (inflight_preloads_.contains(link->href) ||
       preloaded_resources_.contains(link->href)) {
     return;
diff --git a/content/browser/loader/navigation_early_hints_manager.h b/content/browser/loader/navigation_early_hints_manager.h
index 6052600c8c..83ec1ee 100644
--- a/content/browser/loader/navigation_early_hints_manager.h
+++ b/content/browser/loader/navigation_early_hints_manager.h
@@ -73,6 +73,9 @@
   // responses for main frame navigation.
   bool WasPreloadLinkHeaderReceived() const;
 
+  // True when there are at least one inflight preloads.
+  bool HasInflightPreloads() const;
+
   void WaitForPreloadsFinishedForTesting(
       base::OnceCallback<void(PreloadedResources)> callback);
 
diff --git a/content/browser/loader/navigation_early_hints_manager_unittest.cc b/content/browser/loader/navigation_early_hints_manager_unittest.cc
index 38b4010..bf740774 100644
--- a/content/browser/loader/navigation_early_hints_manager_unittest.cc
+++ b/content/browser/loader/navigation_early_hints_manager_unittest.cc
@@ -172,4 +172,21 @@
   EXPECT_TRUE(it->second.was_canceled);
 }
 
+TEST_F(NavigationEarlyHintsManagerTest, PreloadSchemeIsUnsupported) {
+  auto link_header = network::mojom::LinkHeader::New(
+      GURL("file:///"), network::mojom::LinkRelAttribute::kPreload,
+      network::mojom::LinkAsAttribute::kUnspecified,
+      network::mojom::CrossOriginAttribute::kUnspecified,
+      /*mime_type=*/absl::nullopt);
+  auto hints = network::mojom::EarlyHints::New();
+  hints->headers = network::mojom::ParsedHeaders::New();
+  hints->headers->link_headers.push_back(std::move(link_header));
+
+  early_hints_manager().HandleEarlyHints(std::move(hints),
+                                         CreateNavigationResourceRequest());
+
+  EXPECT_TRUE(early_hints_manager().WasPreloadLinkHeaderReceived());
+  EXPECT_FALSE(early_hints_manager().HasInflightPreloads());
+}
+
 }  // namespace content
diff --git a/content/browser/loader/object_navigation_fallback_body_loader.cc b/content/browser/loader/object_navigation_fallback_body_loader.cc
index e90e769..4290ddfd 100644
--- a/content/browser/loader/object_navigation_fallback_body_loader.cc
+++ b/content/browser/loader/object_navigation_fallback_body_loader.cc
@@ -160,31 +160,12 @@
     if (!timing_info->allow_redirect_details) {
       timing_info->start_time = response_head.load_timing.request_start;
     }
-
-    // Accumulate `encoded_data_length` of intermediate redirects into
-    // `transfer_size`. The encoded data length of the final response will be
-    // added later.
-    const GURL* current_url = &initial_url;
-    for (size_t i = 0; i < commit_params.redirect_infos.size(); ++i) {
-      if (url::Origin::Create(*current_url)
-              .IsSameOriginWith(url::Origin::Create(
-                  commit_params.redirect_infos[i].new_url))) {
-        timing_info->transfer_size +=
-            commit_params.redirect_response[i]->encoded_data_length;
-        current_url = &commit_params.redirect_infos[i].new_url;
-      } else {
-        // Any cross-origin redirects zeros out the transfer size and prevents
-        // counting the transfer size of *all* redirects.
-        timing_info->transfer_size = 0;
-        break;
-      }
-    }
   } else {
     timing_info->allow_redirect_details = false;
     timing_info->last_redirect_end_time = base::TimeTicks();
   }
-  // The final value for `transfer_size`, as well as `encoded_body_size`, and
-  // `decoded_body_size` will be populated after loading the body.
+  // The final value for `encoded_body_size` and `decoded_body_size` will be
+  // populated after loading the body.
   timing_info->did_reuse_connection = response_head.load_timing.socket_reused;
   // Use url::Origin to handle cases like blob:https://.
   timing_info->is_secure_transport = base::Contains(
@@ -284,7 +265,6 @@
   }
 
   timing_info_->response_end = status_->completion_time;
-  timing_info_->transfer_size += status_->encoded_data_length;
   timing_info_->encoded_body_size = status_->encoded_body_length;
   timing_info_->decoded_body_size = status_->decoded_body_length;
 
diff --git a/content/browser/media/session/media_session_controller.cc b/content/browser/media/session/media_session_controller.cc
index 13688d95..0d8e483 100644
--- a/content/browser/media/session/media_session_controller.cc
+++ b/content/browser/media/session/media_session_controller.cc
@@ -203,13 +203,15 @@
 }
 
 bool MediaSessionController::IsMediaSessionNeeded() const {
+  if (web_contents_->HasPictureInPictureVideo())
+    return true;
+
   if (!is_playback_in_progress_)
     return false;
 
   // We want to make sure we do not request audio focus on a muted tab as it
   // would break user expectations by pausing/ducking other playbacks.
-  const bool has_audio = has_audio_ && !web_contents_->IsAudioMuted();
-  return has_audio || web_contents_->HasPictureInPictureVideo();
+  return has_audio_ && !web_contents_->IsAudioMuted();
 }
 
 bool MediaSessionController::AddOrRemovePlayer() {
diff --git a/content/browser/media/session/media_session_controller_unittest.cc b/content/browser/media/session/media_session_controller_unittest.cc
index 8e7a205..76131e3 100644
--- a/content/browser/media/session/media_session_controller_unittest.cc
+++ b/content/browser/media/session/media_session_controller_unittest.cc
@@ -579,6 +579,34 @@
   EXPECT_FALSE(media_session()->IsActive());
 }
 
+TEST_F(MediaSessionControllerTest, EndOfPlaybackWithInPictureInPicture) {
+  contents()->SetHasPictureInPictureVideo(true);
+  controller_->PictureInPictureStateChanged(true);
+
+  controller_->SetMetadata(
+      /*has_audio=*/true, /*has_video=*/false,
+      media::MediaContentType::Persistent);
+  ASSERT_TRUE(controller_->OnPlaybackStarted());
+  EXPECT_TRUE(media_session()->IsActive());
+  EXPECT_TRUE(media_session()->IsControllable());
+
+  // Keeping the PiP window open should keep the session controllable.
+  controller_->OnPlaybackPaused(/*reached_end_of_stream=*/true);
+  EXPECT_FALSE(media_session()->IsActive());
+  EXPECT_TRUE(media_session()->IsControllable());
+
+  contents()->SetHasPictureInPictureVideo(false);
+  controller_->PictureInPictureStateChanged(false);
+  EXPECT_FALSE(media_session()->IsActive());
+  EXPECT_FALSE(media_session()->IsControllable());
+
+  // Re-opening the PiP window makes the session controllable again.
+  contents()->SetHasPictureInPictureVideo(true);
+  controller_->PictureInPictureStateChanged(true);
+  EXPECT_FALSE(media_session()->IsActive());
+  EXPECT_TRUE(media_session()->IsControllable());
+}
+
 TEST_F(MediaSessionControllerTest, HasVideo_True) {
   controller_->SetMetadata(
       /* has_audio = */ true, /* has_video = */ true,
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index ce8638f..a7756939 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -1664,8 +1664,7 @@
           states->push_back(MediaAudioVideoState::kAudioVideo);
         } else if (has_audio) {
           states->push_back(MediaAudioVideoState::kAudioOnly);
-        } else {
-          DCHECK(has_video);
+        } else if (has_video) {
           states->push_back(MediaAudioVideoState::kVideoOnly);
         }
       },
diff --git a/content/browser/picture_in_picture/picture_in_picture_content_browsertest.cc b/content/browser/picture_in_picture/picture_in_picture_content_browsertest.cc
index 0305266..de71900 100644
--- a/content/browser/picture_in_picture/picture_in_picture_content_browsertest.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_content_browsertest.cc
@@ -31,10 +31,10 @@
   ~TestOverlayWindow() override = default;
 
   bool IsActive() override { return false; }
-  void Close() override {}
-  void ShowInactive() override {}
-  void Hide() override {}
-  bool IsVisible() override { return false; }
+  void Close() override { visible_ = false; }
+  void ShowInactive() override { visible_ = true; }
+  void Hide() override { visible_ = false; }
+  bool IsVisible() override { return visible_; }
   bool IsAlwaysOnTop() override { return false; }
   gfx::Rect GetBounds() override { return gfx::Rect(size_); }
   void UpdateVideoSize(const gfx::Size& natural_size) override {
@@ -60,6 +60,11 @@
   }
 
  private:
+  // We maintain the visibility state so that
+  // PictureInPictureWindowControllerImpl::Close() sees that the window is
+  // visible and proceeds to initiate leaving PiP.
+  bool visible_ = false;
+
   gfx::Size size_;
   absl::optional<PlaybackState> playback_state_;
 
@@ -459,6 +464,48 @@
             OverlayWindow::PlaybackState::kPlaying);
 }
 
+// Tests Media Session action availability upon reaching the end of stream by
+// verifying that the "nexttrack" action can be invoked after playing through
+// to the end of media.
+IN_PROC_BROWSER_TEST_F(MediaSessionPictureInPictureContentBrowserTest,
+                       ActionAvailableAfterEndOfStreamAndSrcUpdate) {
+  ASSERT_TRUE(NavigateToURL(
+      shell(), GetTestUrl("media/picture_in_picture", "one-video.html")));
+
+  ASSERT_TRUE(ExecJs(shell(), "setMediaSessionNextTrackActionHandler();"));
+  ASSERT_TRUE(ExecJs(shell(), "addPictureInPictureEventListeners();"));
+  ASSERT_EQ(true, EvalJs(shell(), "enterPictureInPicture();"));
+
+  // Check twice, because the action handler updates the 'src' attribute and we
+  // want to make sure this doesn't break the action handling.
+  for (int i = 0; i < 2; ++i) {
+    // Play through to the end of the media resource.
+    ASSERT_EQ(true, EvalJs(shell(), "playToEnd();"));
+    WaitForPlaybackState(OverlayWindow::PlaybackState::kEndOfVideo);
+
+    // Simulate the user clicking the "next track" button and verify the
+    // associated Media Session action that we set earlier is invoked.
+    window_controller()->NextTrack();
+    WaitForPlaybackState(OverlayWindow::PlaybackState::kPlaying);
+  }
+
+  // After closing and reopening the PiP window the Media Session action should
+  // still work.
+  ASSERT_EQ(true, EvalJs(shell(), "playToEnd();"));
+  WaitForPlaybackState(OverlayWindow::PlaybackState::kEndOfVideo);
+
+  window_controller()->Close(/*should_pause_video=*/false);
+  const std::u16string expected_title = u"leavepictureinpicture";
+  EXPECT_EQ(
+      expected_title,
+      TitleWatcher(shell()->web_contents(), expected_title).WaitAndGetTitle());
+
+  ASSERT_EQ(true, EvalJs(shell(), "enterPictureInPicture();"));
+
+  window_controller()->NextTrack();
+  WaitForPlaybackState(OverlayWindow::PlaybackState::kPlaying);
+}
+
 class AutoPictureInPictureContentBrowserTest
     : public PictureInPictureContentBrowserTest {
  public:
diff --git a/content/browser/prerender/prerender_browsertest.cc b/content/browser/prerender/prerender_browsertest.cc
index 4aa694ba..55dd251 100644
--- a/content/browser/prerender/prerender_browsertest.cc
+++ b/content/browser/prerender/prerender_browsertest.cc
@@ -18,17 +18,23 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/thread_annotations.h"
 #include "build/build_config.h"
+#include "components/services/storage/public/mojom/storage_service.mojom.h"
+#include "components/services/storage/public/mojom/test_api.test-mojom.h"
 #include "content/browser/file_system_access/file_system_chooser_test_helpers.h"
 #include "content/browser/prerender/prerender_host.h"
 #include "content/browser/prerender/prerender_host_registry.h"
 #include "content/browser/prerender/prerender_metrics.h"
+#include "content/browser/renderer_host/back_forward_cache_impl.h"
 #include "content/browser/renderer_host/frame_tree_node.h"
 #include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/content_navigation_policy.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_document_host_user_data.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
@@ -237,12 +243,13 @@
     return prerender_helper_.get();
   }
 
- private:
-  void SetUpCommandLine(base::CommandLine* command_line) final {
+  void SetUpCommandLine(base::CommandLine* command_line) override {
     // Useful for testing CSP:prefetch-src
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableExperimentalWebPlatformFeatures);
   }
+
+ private:
   net::test_server::EmbeddedTestServer ssl_server_{
       net::test_server::EmbeddedTestServer::TYPE_HTTPS};
 
@@ -1781,6 +1788,280 @@
   EXPECT_EQ(GetRequestCount(kImageUrl), 1);
 }
 
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+                       SessionStorageAfterBackNavigation_NoProcessReuse) {
+  // When BackForwardCache feature is enabled, this test doesn't work, because
+  // this test is checking the behavior of a new renderer process which is
+  // created for a back forward navigation from a prerendered page.
+  if (IsBackForwardCacheEnabled())
+    return;
+
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  std::unique_ptr<RenderProcessHostWatcher> process_host_watcher =
+      std::make_unique<RenderProcessHostWatcher>(
+          current_frame_host()->GetProcess(),
+          RenderProcessHostWatcher::WATCH_FOR_HOST_DESTRUCTION);
+
+  AddPrerender(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+
+  // Make sure that the initial renderer process is destroyed. So that the
+  // initial renderer process will not be reused after the back forward
+  // navigation below.
+  process_host_watcher->Wait();
+
+  // Navigate back to the initial page.
+  content::TestNavigationObserver observer(shell()->web_contents());
+  shell()->GoBackOrForward(-1);
+  observer.Wait();
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl);
+
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+                       SessionStorageAfterBackNavigation_KeepInitialProcess) {
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  RenderProcessHostImpl* initial_process_host =
+      static_cast<RenderProcessHostImpl*>(current_frame_host()->GetProcess());
+  // Increment the keep alive ref count of the renderer process to keep it alive
+  // so it is reused on the back navigation below. The test checks that the
+  // session storage state changed in the activated page is correctly propagated
+  // after a back navigation that uses an existing renderer process. (Note: This
+  // is not working correctly now.)
+  initial_process_host->IncrementKeepAliveRefCount();
+
+  AddPrerender(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+
+  // Navigate back to the initial page.
+  content::TestNavigationObserver observer(shell()->web_contents());
+  shell()->GoBackOrForward(-1);
+  observer.Wait();
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl);
+
+  // There is a known issue that when the initial renderer process is reused
+  // after the back navigation, the session storage state changed in the
+  // activated is not correctly propagated to the initial renderer process.
+  // TODO(crbug.com/1197383): Fix this issue.
+  EXPECT_EQ(
+      // This should be "activated, initial".
+      "initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+
+class PrerenderSingleProcessBrowserTest : public PrerenderBrowserTest {
+ public:
+  PrerenderSingleProcessBrowserTest() = default;
+
+  void SetUpCommandLine(base::CommandLine* cmd_line) override {
+    PrerenderBrowserTest::SetUpCommandLine(cmd_line);
+    cmd_line->AppendSwitch("single-process");
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(PrerenderSingleProcessBrowserTest,
+                       SessionStorageAfterBackNavigation) {
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  AddPrerender(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+
+  // Navigate back to the initial page.
+  content::TestNavigationObserver observer(shell()->web_contents());
+  shell()->GoBackOrForward(-1);
+  observer.Wait();
+  EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl);
+
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+
+class PrerenderBackForwardCacheBrowserTest : public PrerenderBrowserTest {
+ public:
+  PrerenderBackForwardCacheBrowserTest() {
+    feature_list_.InitWithFeaturesAndParameters(
+        {{features::kBackForwardCache, {{"enable_same_site", "true"}}},
+         {kBackForwardCacheNoTimeEviction, {}}},
+        // Allow BackForwardCache for all devices regardless of their memory.
+        {features::kBackForwardCacheMemoryControls});
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(PrerenderBackForwardCacheBrowserTest,
+                       SessionStorageAfterBackNavigation) {
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  RenderFrameDeletedObserver deleted_observer(
+      shell()->web_contents()->GetMainFrame());
+
+  AddPrerender(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+
+  // Navigate back to the initial page.
+  shell()->GoBackOrForward(-1);
+  WaitForLoadStop(shell()->web_contents());
+
+  // Expect the navigation to be served from the back-forward cache to verify
+  // the test is testing what is intended.
+  ASSERT_EQ(shell()->web_contents()->GetMainFrame(),
+            deleted_observer.render_frame_host());
+
+  // There is a known issue that when the initial renderer process is reused
+  // after the back navigation, the session storage state changed in the
+  // activated is not correctly propagated to the initial renderer process.
+  // TODO(crbug.com/1197383): Fix this issue.
+  EXPECT_EQ(
+      // This should be "activated, initial".
+      "initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+
+#if !defined(OS_ANDROID)
+// StorageServiceOutOfProcess is not implemented on Android.
+
+class PrerenderRestartStorageServiceBrowserTest : public PrerenderBrowserTest {
+ public:
+  PrerenderRestartStorageServiceBrowserTest() {
+    // These tests only make sense when the service is running
+    // out-of-process.
+    feature_list_.InitAndEnableFeature(features::kStorageServiceOutOfProcess);
+  }
+
+ protected:
+  void CrashStorageServiceAndWaitForRestart() {
+    mojo::Remote<storage::mojom::StorageService>& service =
+        StoragePartitionImpl::GetStorageServiceForTesting();
+    base::RunLoop loop;
+    service.set_disconnect_handler(base::BindLambdaForTesting([&] {
+      loop.Quit();
+      service.reset();
+    }));
+    mojo::Remote<storage::mojom::TestApi> test_api;
+    StoragePartitionImpl::GetStorageServiceForTesting()->BindTestApi(
+        test_api.BindNewPipeAndPassReceiver().PassPipe());
+    test_api->CrashNow();
+    loop.Run();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(PrerenderRestartStorageServiceBrowserTest,
+                       RestartStorageServiceBeforePrerendering) {
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  CrashStorageServiceAndWaitForRestart();
+
+  EXPECT_EQ(
+      "initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+
+  AddPrerender(kPrerenderingUrl);
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+
+IN_PROC_BROWSER_TEST_F(PrerenderRestartStorageServiceBrowserTest,
+                       RestartStorageServiceWhilePrerendering) {
+  const GURL kInitialUrl = GetUrl("/prerender/session_storage.html");
+  const GURL kPrerenderingUrl =
+      GetUrl("/prerender/session_storage.html?prerendering=");
+
+  // Navigate to an initial page.
+  ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
+
+  const int host_id = AddPrerender(kPrerenderingUrl);
+
+  CrashStorageServiceAndWaitForRestart();
+
+  EXPECT_EQ(
+      "initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+  EXPECT_EQ(
+      "initial, prerendering",
+      EvalJs(GetPrerenderedMainFrameHost(host_id), "getSessionStorageKeys()")
+          .ExtractString());
+
+  NavigatePrimaryPage(kPrerenderingUrl);
+
+  EXPECT_EQ("initial", EvalJs(current_frame_host(),
+                              "window.sessionKeysInPrerenderingchange")
+                           .ExtractString());
+  EXPECT_EQ(
+      "activated, initial",
+      EvalJs(current_frame_host(), "getSessionStorageKeys()").ExtractString());
+}
+#endif
+
 class PrerenderWithProactiveBrowsingInstanceSwap : public PrerenderBrowserTest {
  public:
   PrerenderWithProactiveBrowsingInstanceSwap() {
diff --git a/content/browser/prerender/prerender_host.cc b/content/browser/prerender/prerender_host.cc
index 41d8cbc..49a819dc 100644
--- a/content/browser/prerender/prerender_host.cc
+++ b/content/browser/prerender/prerender_host.cc
@@ -16,6 +16,7 @@
 #include "content/browser/renderer_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_frame_proxy_host.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/browser/site_instance_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/back_forward_cache.h"
 #include "content/public/browser/navigation_controller.h"
@@ -77,10 +78,20 @@
                                         &web_contents,
                                         &web_contents,
                                         FrameTree::Type::kPrerender)) {
-    frame_tree_->Init(
-        SiteInstance::Create(web_contents.GetBrowserContext()).get(),
-        /*renderer_initiated_creation=*/false,
-        /*main_frame_name=*/"");
+    scoped_refptr<SiteInstance> site_instance =
+        SiteInstance::Create(web_contents.GetBrowserContext());
+    frame_tree_->Init(site_instance.get(),
+                      /*renderer_initiated_creation=*/false,
+                      /*main_frame_name=*/"");
+
+    const auto& site_info =
+        static_cast<SiteInstanceImpl*>(site_instance.get())->GetSiteInfo();
+    // Use the same SessionStorageNamespace as the primary page for the
+    // prerendering page.
+    frame_tree_->controller().SetSessionStorageNamespace(
+        site_info.GetStoragePartitionId(site_instance->GetBrowserContext()),
+        web_contents_.GetFrameTree()->controller().GetSessionStorageNamespace(
+            site_info));
 
     // TODO(https://crbug.com/1199679): This should be moved to FrameTree::Init
     web_contents_.NotifySwappedFromRenderManager(
diff --git a/content/browser/renderer_host/DIR_METADATA b/content/browser/renderer_host/DIR_METADATA
index 566b56ab..4f025c8 100644
--- a/content/browser/renderer_host/DIR_METADATA
+++ b/content/browser/renderer_host/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Internals>Core"
-}
 # COMPONENT: Internals>Sandbox>SiteIsolation
 team_email: "site-isolation-dev@chromium.org"
diff --git a/content/browser/renderer_host/back_forward_cache_impl.cc b/content/browser/renderer_host/back_forward_cache_impl.cc
index 830c9af..5c5d52d 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.cc
+++ b/content/browser/renderer_host/back_forward_cache_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/barrier_closure.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/typed_macros.h"
@@ -39,11 +40,6 @@
 
 using blink::scheduler::WebSchedulerTrackedFeature;
 
-// Removes the time limit for cached content. This is used on bots to identify
-// accidentally passing tests.
-const base::Feature kBackForwardCacheNoTimeEviction{
-    "BackForwardCacheNoTimeEviction", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // The default number of entries the BackForwardCache can hold per tab.
 static constexpr size_t kDefaultBackForwardCacheSize = 1;
 
@@ -336,6 +332,18 @@
   return false;
 }
 
+// Returns true if all of the RenderViewHosts in this Entry have received the
+// acknowledgement from renderer.
+bool AllRenderViewHostsReceivedAckFromRenderer(
+    BackForwardCacheImpl::Entry& entry) {
+  for (auto* rvh : entry.render_view_hosts) {
+    if (!rvh->DidReceiveBackForwardCacheAck()) {
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace
 
 // static
@@ -705,11 +713,16 @@
     size_t limit,
     bool foregrounded_only) {
   size_t count = 0;
+  size_t not_received_ack_count = 0;
   for (auto& stored_entry : entries_) {
     if (stored_entry->render_frame_host->is_evicted_from_back_forward_cache())
       continue;
     if (foregrounded_only && !HasForegroundedProcess(*stored_entry))
       continue;
+    if (!AllRenderViewHostsReceivedAckFromRenderer(*stored_entry)) {
+      not_received_ack_count++;
+      continue;
+    }
     if (++count > limit) {
       stored_entry->render_frame_host->EvictFromBackForwardCacheWithReason(
           foregrounded_only
@@ -718,6 +731,10 @@
               : BackForwardCacheMetrics::NotRestoredReason::kCacheLimit);
     }
   }
+  UMA_HISTOGRAM_COUNTS_100(
+      "BackForwardCache.AllSites.HistoryNavigationOutcome."
+      "CountEntriesWithoutRendererAck",
+      not_received_ack_count);
   return count;
 }
 
diff --git a/content/browser/renderer_host/back_forward_cache_impl.h b/content/browser/renderer_host/back_forward_cache_impl.h
index 7e0e77e..0794d62 100644
--- a/content/browser/renderer_host/back_forward_cache_impl.h
+++ b/content/browser/renderer_host/back_forward_cache_impl.h
@@ -44,6 +44,11 @@
     "RecordBackForwardCacheMetricsWithoutEnabling",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Removes the time limit for cached content. This is used on bots to identify
+// accidentally passing tests.
+constexpr base::Feature kBackForwardCacheNoTimeEviction{
+    "BackForwardCacheNoTimeEviction", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // BackForwardCache:
 //
 // After the user navigates away from a document, the old one goes into the
@@ -74,6 +79,10 @@
     ~Entry();
 
     void WriteIntoTrace(perfetto::TracedValue context);
+    // Indicates whether or not all the |render_view_hosts| in this entry have
+    // received the acknowledgement from renderer that it finished running
+    // handlers.
+    bool AllRenderViewHostsReceivedAckFromRenderer();
 
     // The main document being stored.
     std::unique_ptr<RenderFrameHostImpl> render_frame_host;
diff --git a/content/browser/renderer_host/page_lifecycle_state_manager.cc b/content/browser/renderer_host/page_lifecycle_state_manager.cc
index 523c09d9..e733b29 100644
--- a/content/browser/renderer_host/page_lifecycle_state_manager.cc
+++ b/content/browser/renderer_host/page_lifecycle_state_manager.cc
@@ -214,6 +214,14 @@
   // features into account.
   render_view_host_impl_->MaybeEvictFromBackForwardCache();
 
+  // A page that has not yet received an acknowledgement from renderer is not
+  // counted against the cache size limit because it might still be ineligible
+  // for caching after the ack, i.e., after running handlers. After it receives
+  // the ack and we call |MaybeEvictFromBackForwardCache()|, we know whether it
+  // is eligible for caching and we should reconsider the cache size limits
+  // again.
+  render_view_host_impl_->EnforceBackForwardCacheSizeLimit();
+
   if (last_acknowledged_state_->is_in_back_forward_cache) {
     back_forward_cache_timeout_monitor_.reset(nullptr);
   }
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index e38a3a0..33334db 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -599,6 +599,10 @@
   }
 }
 
+void RenderViewHostImpl::EnforceBackForwardCacheSizeLimit() {
+  frame_tree_->controller().GetBackForwardCache().EnforceCacheSizeLimit();
+}
+
 bool RenderViewHostImpl::DidReceiveBackForwardCacheAck() {
   return GetPageLifecycleStateManager()->DidReceiveBackForwardCacheAck();
 }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 8926801..091395a 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -243,6 +243,7 @@
   void SetIsFrozen(bool frozen);
   void OnBackForwardCacheTimeout();
   void MaybeEvictFromBackForwardCache();
+  void EnforceBackForwardCacheSizeLimit();
 
   PageLifecycleStateManager* GetPageLifecycleStateManager() {
     return page_lifecycle_state_manager_.get();
diff --git a/content/public/android/java/res/DIR_METADATA b/content/public/android/java/res/DIR_METADATA
deleted file mode 100644
index cf3a68f..0000000
--- a/content/public/android/java/res/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Content>Core"
-}
-
-os: ANDROID
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
index 7dd3383..6ad19c3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/DIR_METADATA
@@ -4,4 +4,3 @@
 
 team_email: "chromium-accessibility@chromium.org"
 
-os: ANDROID
diff --git a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DIR_METADATA
deleted file mode 100644
index 7a2580a..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/androidoverlay/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
diff --git a/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA b/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
index c7c4bbd..d6af1cb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
+++ b/content/public/android/java/src/org/chromium/content/browser/font/DIR_METADATA
@@ -4,4 +4,3 @@
 
 team_email: "clank-dev@google.com"
 
-os: ANDROID
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
index fb2ba0e..7a2dd4c7 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
+++ b/content/public/android/javatests/src/org/chromium/content/browser/accessibility/DIR_METADATA
@@ -4,4 +4,3 @@
 
 team_email: "chromium-accessibility@chromium.org"
 
-os: ANDROID
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc
index ee95705..b321408 100644
--- a/content/renderer/v8_value_converter_impl.cc
+++ b/content/renderer/v8_value_converter_impl.cc
@@ -606,8 +606,8 @@
     if (strip_null_from_objects_ && child->is_none())
       continue;
 
-    result->SetWithoutPathExpansion(std::string(*name_utf8, name_utf8.length()),
-                                    std::move(child));
+    result->SetKey(std::string(*name_utf8, name_utf8.length()),
+                   base::Value::FromUniquePtrValue(std::move(child)));
   }
 
   return std::move(result);
diff --git a/content/test/data/back_forward_cache/page_with_broadcastchannel.html b/content/test/data/back_forward_cache/page_with_broadcastchannel.html
index 4829fe8..e3f86c0 100644
--- a/content/test/data/back_forward_cache/page_with_broadcastchannel.html
+++ b/content/test/data/back_forward_cache/page_with_broadcastchannel.html
@@ -5,19 +5,27 @@
 
 let channel;
 let shouldCloseChannelInPageHide;
+let shouldAcquireBroadcastChannelInPageHide;
 
 function acquireBroadcastChannel() {
   channel = new BroadcastChannel('foo');
 }
 
 function setShouldCloseChannelInPageHide(close) {
- shouldCloseChannelInPageHide = close;
+  shouldCloseChannelInPageHide = close;
+}
+
+function setShouldAcquireBroadcastChannelInPageHide(acquire) {
+  shouldAcquireBroadcastChannelInPageHide = acquire;
 }
 
 window.onpagehide = event => {
   if (shouldCloseChannelInPageHide) {
     channel.close();
   }
+  if (shouldAcquireBroadcastChannelInPageHide) {
+    acquireBroadcastChannel();
+  }
 }
 
 </script>
diff --git a/content/test/data/media/picture_in_picture/one-video.html b/content/test/data/media/picture_in_picture/one-video.html
index ea89297..1ee55c4 100644
--- a/content/test/data/media/picture_in_picture/one-video.html
+++ b/content/test/data/media/picture_in_picture/one-video.html
@@ -33,8 +33,29 @@
       return true;
     }
 
+    async function playToEnd() {
+      video.loop = false;
+      await video.play();
+      video.currentTime = video.duration;
+      await _waitForEnded();
+      return true;
+    }
+
+    function _waitForEnded() {
+      return new Promise(resolve => {
+        if (video.ended) {
+          resolve();
+          return;
+        }
+
+        video.addEventListener('ended', () => {
+          resolve();
+        }, { once: true });
+      });
+    }
+
     async function updateVideoSrcAndPlay() {
-      video.src="../tulip2.webm";
+      video.src = "../tulip2.webm";
       await video.play();
       return true;
     }
@@ -46,7 +67,7 @@
     }
 
     function _waitForMetadata() {
-      return new Promise((resolve, _) => {
+      return new Promise(resolve => {
         if (video.readyState >= HTMLMediaElement.HAVE_METADATA) {
           resolve();
           return;
@@ -74,5 +95,14 @@
         video.pause();
       });
     }
+
+    function setMediaSessionNextTrackActionHandler() {
+      navigator.mediaSession.setActionHandler("nexttrack", _ => {
+        // Simulates a playlist functionality (in this case the playlist has
+        // just one item).
+        video.src = "../tulip2.webm";
+        video.play();
+      });
+    }
   </script>
 </html>
diff --git a/content/test/data/prerender/session_storage.html b/content/test/data/prerender/session_storage.html
new file mode 100644
index 0000000..34efa12a
--- /dev/null
+++ b/content/test/data/prerender/session_storage.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="test_utils.js"></script>
+<script>
+function getSessionStorageKeys() {
+  let keys = [];
+  let txt = '';
+  for (let i = 0; i < sessionStorage.length; ++i) {
+    keys.push(sessionStorage.key(i));
+  }
+  keys.sort();
+  keys.forEach((key) => {
+    if (txt.length) {
+      txt += ', ';
+    }
+    txt += key;
+  });
+  return txt;
+}
+
+(() => {
+  const params = new URLSearchParams(location.search);
+  const isPrerendering = params.has('prerendering');
+  if (!isPrerendering) {
+    sessionStorage.setItem('initial', '1');
+    return;
+  }
+  sessionStorage.setItem('prerendering', '1');
+  window.sessionKeysInPrerenderingchange = new Promise((resolve) => {
+    document.addEventListener('prerenderingchange', () => {
+      resolve(getSessionStorageKeys());
+      sessionStorage.setItem('activated', '1');
+    });
+  });
+})();
+</script>
+</head>
+<body></body>
+</html>
diff --git a/dbus/values_util.cc b/dbus/values_util.cc
index 6f73a84..e7405f9 100644
--- a/dbus/values_util.cc
+++ b/dbus/values_util.cc
@@ -60,7 +60,8 @@
     std::unique_ptr<base::Value> value = PopDataAsValue(&entry_reader);
     if (!value)
       return false;
-    dictionary_value->SetWithoutPathExpansion(key_string, std::move(value));
+    dictionary_value->SetKey(key_string,
+                             base::Value::FromUniquePtrValue(std::move(value)));
   }
   return true;
 }
diff --git a/device/gamepad/DIR_METADATA b/device/gamepad/DIR_METADATA
index 5942cbc..60e948d 100644
--- a/device/gamepad/DIR_METADATA
+++ b/device/gamepad/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "IO>Gamepad"
 }
-team_email: "device-dev@chromium.org"
\ No newline at end of file
diff --git a/device/vr/android/arcore/DIR_METADATA b/device/vr/android/arcore/DIR_METADATA
index f31f70a8..27ea7f1 100644
--- a/device/vr/android/arcore/DIR_METADATA
+++ b/device/vr/android/arcore/DIR_METADATA
@@ -9,5 +9,4 @@
 monorail {
   component: "Blink>WebXR>AR"
 }
-team_email: "xr-dev@chromium.org"
 os: ANDROID
\ No newline at end of file
diff --git a/device/vr/public/mojom/DIR_METADATA b/device/vr/public/mojom/DIR_METADATA
deleted file mode 100644
index 203eb72a..0000000
--- a/device/vr/public/mojom/DIR_METADATA
+++ /dev/null
@@ -1,12 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>XR"
-}
-team_email: "xr-dev@chromium.org"
\ No newline at end of file
diff --git a/extensions/browser/api/bluetooth_low_energy/utils.cc b/extensions/browser/api/bluetooth_low_energy/utils.cc
index a6dca2c..98987a52 100644
--- a/extensions/browser/api/bluetooth_low_energy/utils.cc
+++ b/extensions/browser/api/bluetooth_low_energy/utils.cc
@@ -35,8 +35,8 @@
   std::vector<CharacteristicProperty> properties = from->properties;
   from->properties.clear();
   std::unique_ptr<base::DictionaryValue> to = from->ToValue();
-  to->SetWithoutPathExpansion("properties",
-                              CharacteristicPropertiesToValue(properties));
+  to->SetKey("properties", base::Value::FromUniquePtrValue(
+                               CharacteristicPropertiesToValue(properties)));
   return to;
 }
 
@@ -53,8 +53,9 @@
   base::DictionaryValue* chrc_value = NULL;
   to->GetDictionaryWithoutPathExpansion("characteristic", &chrc_value);
   DCHECK(chrc_value);
-  chrc_value->SetWithoutPathExpansion(
-      "properties", CharacteristicPropertiesToValue(properties));
+  chrc_value->SetKey("properties",
+                     base::Value::FromUniquePtrValue(
+                         CharacteristicPropertiesToValue(properties)));
   return to;
 }
 
diff --git a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
index d698b02..1c769a2a 100644
--- a/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
+++ b/extensions/browser/api/declarative_webrequest/webrequest_condition_attribute_unittest.cc
@@ -268,7 +268,8 @@
           dictionary->RemoveWithoutPathExpansion(*name, &entry_owned);
           list->Append(std::move(entry_owned));
           list->AppendString(*value);
-          dictionary->SetWithoutPathExpansion(*name, std::move(list));
+          dictionary->SetKey(*name,
+                             base::Value::FromUniquePtrValue(std::move(list)));
           break;
         }
         case base::Value::Type::LIST:  // Just append to the list.
diff --git a/extensions/browser/api/web_request/upload_data_presenter.cc b/extensions/browser/api/web_request/upload_data_presenter.cc
index 58dcdd7c..017234a 100644
--- a/extensions/browser/api/web_request/upload_data_presenter.cc
+++ b/extensions/browser/api/web_request/upload_data_presenter.cc
@@ -43,7 +43,7 @@
                         std::unique_ptr<base::Value> value,
                         base::ListValue* list) {
   std::unique_ptr<base::DictionaryValue> dictionary(new base::DictionaryValue);
-  dictionary->SetWithoutPathExpansion(key, std::move(value));
+  dictionary->SetKey(key, base::Value::FromUniquePtrValue(std::move(value)));
   list->Append(std::move(dictionary));
 }
 
diff --git a/extensions/browser/api/web_request/upload_data_presenter_unittest.cc b/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
index ec6cb77..f8e9448 100644
--- a/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
+++ b/extensions/browser/api/web_request/upload_data_presenter_unittest.cc
@@ -29,7 +29,8 @@
   std::unique_ptr<base::ListValue> values(new base::ListValue);
   values->AppendString("value");
   base::DictionaryValue expected_form;
-  expected_form.SetWithoutPathExpansion("key.with.dots", std::move(values));
+  expected_form.SetKey("key.with.dots",
+                       base::Value::FromUniquePtrValue(std::move(values)));
 
   // Real output.
   std::unique_ptr<ParsedDataPresenter> parsed_data_presenter(
diff --git a/extensions/browser/app_window/app_window_geometry_cache.cc b/extensions/browser/app_window/app_window_geometry_cache.cc
index c9d569a6..0c1310d 100644
--- a/extensions/browser/app_window/app_window_geometry_cache.cc
+++ b/extensions/browser/app_window/app_window_geometry_cache.cc
@@ -120,7 +120,8 @@
       value->SetInteger("state", it->second.window_state);
       value->SetString(
           "ts", base::NumberToString(it->second.last_change.ToInternalValue()));
-      dict->SetWithoutPathExpansion(it->first, std::move(value));
+      dict->SetKey(it->first,
+                   base::Value::FromUniquePtrValue(std::move(value)));
 
       for (auto& observer : observers_)
         observer.OnGeometryCacheChanged(extension_id, it->first, bounds);
diff --git a/extensions/browser/app_window/app_window_geometry_cache_unittest.cc b/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
index 4a72a58..bcafcd4f 100644
--- a/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
+++ b/extensions/browser/app_window/app_window_geometry_cache_unittest.cc
@@ -94,7 +94,7 @@
   value->SetInteger("screen_bounds_w", screen_bounds.width());
   value->SetInteger("screen_bounds_h", screen_bounds.height());
   value->SetInteger("state", state);
-  dict->SetWithoutPathExpansion(window_id, std::move(value));
+  dict->SetKey(window_id, base::Value::FromUniquePtrValue(std::move(value)));
   extension_prefs_->SetGeometryCache(extension_id, std::move(dict));
   LoadExtension(extension_id);
 }
diff --git a/extensions/browser/content_verifier/DIR_METADATA b/extensions/browser/content_verifier/DIR_METADATA
deleted file mode 100644
index 55432ec..0000000
--- a/extensions/browser/content_verifier/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
diff --git a/extensions/browser/updater/DIR_METADATA b/extensions/browser/updater/DIR_METADATA
deleted file mode 100644
index 81a57a13..0000000
--- a/extensions/browser/updater/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
-team_email: "extensions-dev@chromium.org"
diff --git a/extensions/browser/value_store/testing_value_store.cc b/extensions/browser/value_store/testing_value_store.cc
index e472ffb..6f05128e 100644
--- a/extensions/browser/value_store/testing_value_store.cc
+++ b/extensions/browser/value_store/testing_value_store.cc
@@ -62,8 +62,7 @@
   for (auto it = keys.cbegin(); it != keys.cend(); ++it) {
     base::Value* value = NULL;
     if (storage_.GetWithoutPathExpansion(*it, &value)) {
-      settings->SetWithoutPathExpansion(
-          *it, base::Value::ToUniquePtrValue(value->Clone()));
+      settings->SetKey(*it, value->Clone());
     }
   }
   return ReadResult(std::move(settings), CreateStatusCopy(status_));
@@ -79,8 +78,7 @@
 ValueStore::WriteResult TestingValueStore::Set(
     WriteOptions options, const std::string& key, const base::Value& value) {
   base::DictionaryValue settings;
-  settings.SetWithoutPathExpansion(
-      key, base::Value::ToUniquePtrValue(value.Clone()));
+  settings.SetKey(key, value.Clone());
   return Set(options, settings);
 }
 
@@ -101,8 +99,7 @@
                                ? absl::optional<base::Value>(old_value->Clone())
                                : absl::nullopt,
                            it.value().Clone());
-      storage_.SetWithoutPathExpansion(
-          it.key(), base::Value::ToUniquePtrValue(it.value().Clone()));
+      storage_.SetKey(it.key(), it.value().Clone());
     }
   }
   return WriteResult(std::move(changes), CreateStatusCopy(status_));
diff --git a/extensions/browser/value_store/value_store_unittest.cc b/extensions/browser/value_store/value_store_unittest.cc
index 7e0bf4f..76f71b84 100644
--- a/extensions/browser/value_store/value_store_unittest.cc
+++ b/extensions/browser/value_store/value_store_unittest.cc
@@ -318,7 +318,8 @@
   std::vector<std::string> dot_list;
   dot_list.push_back(dot_key);
   base::DictionaryValue dot_dict;
-  dot_dict.SetWithoutPathExpansion(dot_key, dot_value.CreateDeepCopy());
+  dot_dict.SetKey(dot_key,
+                  base::Value::FromUniquePtrValue(dot_value.CreateDeepCopy()));
 
   EXPECT_PRED_FORMAT2(SettingsEq, *empty_dict_, storage_->Get(dot_key));
 
diff --git a/extensions/common/api/DIR_METADATA b/extensions/common/api/DIR_METADATA
index e16d0d54..637eb4dc 100644
--- a/extensions/common/api/DIR_METADATA
+++ b/extensions/common/api/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Platform>Extensions>API"
 }
-team_email: "extensions-dev@chromium.org"
diff --git a/extensions/renderer/DIR_METADATA b/extensions/renderer/DIR_METADATA
deleted file mode 100644
index 55432ec..0000000
--- a/extensions/renderer/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Platform>Extensions"
-}
diff --git a/extensions/renderer/bindings/argument_spec.cc b/extensions/renderer/bindings/argument_spec.cc
index 63dc9eac..39f5b40 100644
--- a/extensions/renderer/bindings/argument_spec.cc
+++ b/extensions/renderer/bindings/argument_spec.cc
@@ -564,8 +564,7 @@
       }
       if (preserve_null_ && prop_value->IsNull()) {
         if (result) {
-          result->SetWithoutPathExpansion(*utf8_key,
-                                          std::make_unique<base::Value>());
+          result->SetKey(*utf8_key, base::Value());
         }
         if (convert_to_v8)
           v8_result.Set(*utf8_key, prop_value);
@@ -584,7 +583,8 @@
       return false;
     }
     if (out_value)
-      result->SetWithoutPathExpansion(*utf8_key, std::move(property));
+      result->SetKey(*utf8_key,
+                     base::Value::FromUniquePtrValue(std::move(property)));
     if (convert_to_v8)
       v8_result.Set(*utf8_key, v8_property);
   }
diff --git a/google_apis/gaia/DIR_METADATA b/google_apis/gaia/DIR_METADATA
deleted file mode 100644
index 3f72231..0000000
--- a/google_apis/gaia/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Services>SignIn"
-}
\ No newline at end of file
diff --git a/gpu/GLES2/DIR_METADATA b/gpu/GLES2/DIR_METADATA
deleted file mode 100644
index 8e87cca..0000000
--- a/gpu/GLES2/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
diff --git a/gpu/command_buffer/DIR_METADATA b/gpu/command_buffer/DIR_METADATA
deleted file mode 100644
index 8e87cca..0000000
--- a/gpu/command_buffer/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 5449150..d8137c45 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
index 3958e05..c27e621 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <utility>
 
+#include "base/containers/contains.h"
 #include "base/feature_list.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
diff --git a/gpu/config/DIR_METADATA b/gpu/config/DIR_METADATA
deleted file mode 100644
index 8e87cca..0000000
--- a/gpu/config/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
diff --git a/gpu/ipc/host/gpu_memory_buffer_support.cc b/gpu/ipc/host/gpu_memory_buffer_support.cc
index 2ee6c02..8d4851ef 100644
--- a/gpu/ipc/host/gpu_memory_buffer_support.cc
+++ b/gpu/ipc/host/gpu_memory_buffer_support.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
 
+#include "base/containers/contains.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
diff --git a/gpu/vulkan/DIR_METADATA b/gpu/vulkan/DIR_METADATA
deleted file mode 100644
index 8e87cca..0000000
--- a/gpu/vulkan/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>GPU>Internals"
-}
\ No newline at end of file
diff --git a/headless/lib/browser/headless_clipboard.cc b/headless/lib/browser/headless_clipboard.cc
index 92c6a13..e076898 100644
--- a/headless/lib/browser/headless_clipboard.cc
+++ b/headless/lib/browser/headless_clipboard.cc
@@ -4,6 +4,7 @@
 
 #include "headless/lib/browser/headless_clipboard.h"
 
+#include "base/containers/contains.h"
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/infra/config/DIR_METADATA b/infra/config/DIR_METADATA
deleted file mode 100644
index d2d9af5..0000000
--- a/infra/config/DIR_METADATA
+++ /dev/null
@@ -1,12 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Infra>Client>Chrome"
-}
-team_email: "infra-dev@chromium.org"
\ No newline at end of file
diff --git a/ios/build/DIR_METADATA b/ios/build/DIR_METADATA
index 7ebb225..3a18da1e 100644
--- a/ios/build/DIR_METADATA
+++ b/ios/build/DIR_METADATA
@@ -9,5 +9,3 @@
 monorail {
   component: "Infra>Client>Chrome"
 }
-team_email: "ios-directory-owners@chromium.org"
-os: IOS
\ No newline at end of file
diff --git a/ios/chrome/DIR_METADATA b/ios/chrome/DIR_METADATA
deleted file mode 100644
index eb25a3b5..0000000
--- a/ios/chrome/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI>Browser>Mobile"
-}
\ No newline at end of file
diff --git a/ios/chrome/browser/DIR_METADATA b/ios/chrome/browser/DIR_METADATA
deleted file mode 100644
index eb25a3b5..0000000
--- a/ios/chrome/browser/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI>Browser>Mobile"
-}
\ No newline at end of file
diff --git a/ios/chrome/browser/commerce/DIR_METADATA b/ios/chrome/browser/commerce/DIR_METADATA
index b104c6d..2cb1250 100644
--- a/ios/chrome/browser/commerce/DIR_METADATA
+++ b/ios/chrome/browser/commerce/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Shopping"
 }
-os: IOS
diff --git a/ios/chrome/browser/link_to_text/DIR_METADATA b/ios/chrome/browser/link_to_text/DIR_METADATA
deleted file mode 100644
index fd0c786e..0000000
--- a/ios/chrome/browser/link_to_text/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "ios-directory-owners@chromium.org"
-os: IOS
diff --git a/ios/chrome/browser/ui/commerce/DIR_METADATA b/ios/chrome/browser/ui/commerce/DIR_METADATA
index b104c6d..2cb1250 100644
--- a/ios/chrome/browser/ui/commerce/DIR_METADATA
+++ b/ios/chrome/browser/ui/commerce/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "UI>Browser>Shopping"
 }
-os: IOS
diff --git a/ios/chrome/browser/ui/link_to_text/DIR_METADATA b/ios/chrome/browser/ui/link_to_text/DIR_METADATA
deleted file mode 100644
index fd0c786e..0000000
--- a/ios/chrome/browser/ui/link_to_text/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "ios-directory-owners@chromium.org"
-os: IOS
diff --git a/ios/showcase/DIR_METADATA b/ios/showcase/DIR_METADATA
deleted file mode 100644
index eb25a3b5..0000000
--- a/ios/showcase/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI>Browser>Mobile"
-}
\ No newline at end of file
diff --git a/ios/third_party/DIR_METADATA b/ios/third_party/DIR_METADATA
deleted file mode 100644
index eb25a3b5..0000000
--- a/ios/third_party/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI>Browser>Mobile"
-}
\ No newline at end of file
diff --git a/ios/web/browsing_data/DIR_METADATA b/ios/web/browsing_data/DIR_METADATA
deleted file mode 100644
index 78e07203..0000000
--- a/ios/web/browsing_data/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Mobile>iOSWeb"
-}
\ No newline at end of file
diff --git a/ios/web/favicon/DIR_METADATA b/ios/web/favicon/DIR_METADATA
deleted file mode 100644
index 78e07203..0000000
--- a/ios/web/favicon/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Mobile>iOSWeb"
-}
\ No newline at end of file
diff --git a/ios/web/init/DIR_METADATA b/ios/web/init/DIR_METADATA
deleted file mode 100644
index 78e07203..0000000
--- a/ios/web/init/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Mobile>iOSWeb"
-}
\ No newline at end of file
diff --git a/ios/web/public/thread/DIR_METADATA b/ios/web/public/thread/DIR_METADATA
deleted file mode 100644
index 78e07203..0000000
--- a/ios/web/public/thread/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Mobile>iOSWeb"
-}
\ No newline at end of file
diff --git a/ios/web/thread/DIR_METADATA b/ios/web/thread/DIR_METADATA
deleted file mode 100644
index 78e07203..0000000
--- a/ios/web/thread/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Mobile>iOSWeb"
-}
\ No newline at end of file
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
index f204948f..ca5fa656 100644
--- a/ipc/ipc_channel_proxy.cc
+++ b/ipc/ipc_channel_proxy.cc
@@ -11,6 +11,7 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/containers/contains.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
index 1740d84..4c848850 100644
--- a/ipc/ipc_mojo_bootstrap.cc
+++ b/ipc/ipc_mojo_bootstrap.cc
@@ -16,6 +16,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/check_op.h"
+#include "base/containers/contains.h"
 #include "base/containers/queue.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
diff --git a/media/midi/task_service.cc b/media/midi/task_service.cc
index fb19068..21bb8dc 100644
--- a/media/midi/task_service.cc
+++ b/media/midi/task_service.cc
@@ -151,7 +151,7 @@
 #elif defined(OS_MAC)
     options.message_pump_type = base::MessagePumpType::UI;
 #endif
-    threads_[thread]->StartWithOptions(options);
+    threads_[thread]->StartWithOptions(std::move(options));
   }
   return threads_[thread]->task_runner();
 }
diff --git a/ppapi/examples/video_decode/DIR_METADATA b/ppapi/examples/video_decode/DIR_METADATA
deleted file mode 100644
index 4eeb71e..0000000
--- a/ppapi/examples/video_decode/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Plugins>Pepper"
-}
\ No newline at end of file
diff --git a/ppapi/generators/DIR_METADATA b/ppapi/generators/DIR_METADATA
deleted file mode 100644
index 4eeb71e..0000000
--- a/ppapi/generators/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Plugins>Pepper"
-}
\ No newline at end of file
diff --git a/ppapi/native_client/DIR_METADATA b/ppapi/native_client/DIR_METADATA
deleted file mode 100644
index 4eeb71e..0000000
--- a/ppapi/native_client/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Plugins>Pepper"
-}
\ No newline at end of file
diff --git a/printing/sandbox/DIR_METADATA b/printing/sandbox/DIR_METADATA
deleted file mode 100644
index b4a91a0..0000000
--- a/printing/sandbox/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Internals>Printing"
-}
\ No newline at end of file
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index bf6bc3f..83a4576 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -246,10 +246,17 @@
   if (resource_request.destination ==
       network::mojom::RequestDestination::kWebBundle) {
     DCHECK(resource_request.web_bundle_token_params.has_value());
+
+    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer;
+    if (resource_request.devtools_request_id.has_value()) {
+      devtools_observer = GetDevToolsObserver(resource_request);
+    }
+
     base::WeakPtr<WebBundleURLLoaderFactory> web_bundle_url_loader_factory =
         context_->GetWebBundleManager().CreateWebBundleURLLoaderFactory(
             resource_request.url, *resource_request.web_bundle_token_params,
-            process_id_, request_initiator_origin_lock_);
+            process_id_, request_initiator_origin_lock_,
+            std::move(devtools_observer), resource_request.devtools_request_id);
     client =
         web_bundle_url_loader_factory->WrapURLLoaderClient(std::move(client));
   }
@@ -259,19 +266,8 @@
                         : network_loader_factory_.get();
   DCHECK(inner_url_loader_factory);
   if (!disable_web_security_) {
-    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer;
-    if (resource_request.trusted_params &&
-        resource_request.trusted_params->devtools_observer) {
-      ResourceRequest::TrustedParams cloned_params =
-          *resource_request.trusted_params;
-      devtools_observer = std::move(cloned_params.devtools_observer);
-    } else {
-      mojom::DevToolsObserver* observer =
-          factory_override_ ? factory_override_->GetDevToolsObserver()
-                            : network_loader_factory_->GetDevToolsObserver();
-      if (observer)
-        observer->Clone(devtools_observer.InitWithNewPipeAndPassReceiver());
-    }
+    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer =
+        GetDevToolsObserver(resource_request);
 
     auto loader = std::make_unique<CorsURLLoader>(
         std::move(receiver), process_id_, request_id, options,
@@ -550,6 +546,25 @@
          context_->allow_any_cors_exempt_header_for_browser();
 }
 
+mojo::PendingRemote<mojom::DevToolsObserver>
+CorsURLLoaderFactory::GetDevToolsObserver(
+    const ResourceRequest& resource_request) const {
+  mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer;
+  if (resource_request.trusted_params &&
+      resource_request.trusted_params->devtools_observer) {
+    ResourceRequest::TrustedParams cloned_params =
+        *resource_request.trusted_params;
+    devtools_observer = std::move(cloned_params.devtools_observer);
+  } else {
+    mojom::DevToolsObserver* observer =
+        factory_override_ ? factory_override_->GetDevToolsObserver()
+                          : network_loader_factory_->GetDevToolsObserver();
+    if (observer)
+      observer->Clone(devtools_observer.InitWithNewPipeAndPassReceiver());
+  }
+  return devtools_observer;
+}
+
 }  // namespace cors
 
 }  // namespace network
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index 9372bbe..39b53d6 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -91,6 +91,9 @@
 
   bool GetAllowAnyCorsExemptHeaderForBrowser() const;
 
+  mojo::PendingRemote<mojom::DevToolsObserver> GetDevToolsObserver(
+      const ResourceRequest& resource_request) const;
+
   mojo::ReceiverSet<mojom::URLLoaderFactory> receivers_;
 
   // Used when constructed by NetworkContext.
diff --git a/services/network/first_party_sets/first_party_set_parser.cc b/services/network/first_party_sets/first_party_set_parser.cc
index f3977ca..3fa4ab80 100644
--- a/services/network/first_party_sets/first_party_set_parser.cc
+++ b/services/network/first_party_sets/first_party_set_parser.cc
@@ -60,7 +60,7 @@
 
 // Parses a single First-Party Set into a map from member to owner (including an
 // entry owner -> owner). Note that this is intended for use *only* on sets that
-// were preloaded via the component updater, so this does not check assertions
+// were received via the Component Updater, so this does not check assertions
 // or versions. It rejects sets which are non-disjoint with
 // previously-encountered sets (i.e. sets which have non-empty intersections
 // with `elements`), and singleton sets (i.e. sets must have an owner and at
@@ -70,10 +70,9 @@
 // and augments `elements` to include the elements of the set that was parsed.
 //
 // Returns true if parsing and validation were successful, false otherwise.
-bool ParsePreloadedSet(
-    const base::Value& value,
-    base::flat_map<net::SchemefulSite, net::SchemefulSite>& map,
-    base::flat_set<net::SchemefulSite>& elements) {
+bool ParseSet(const base::Value& value,
+              base::flat_map<net::SchemefulSite, net::SchemefulSite>& map,
+              base::flat_set<net::SchemefulSite>& elements) {
   if (!value.is_dict())
     return false;
 
@@ -127,7 +126,7 @@
 }
 
 std::unique_ptr<base::flat_map<net::SchemefulSite, net::SchemefulSite>>
-FirstPartySetParser::ParsePreloadedSets(base::StringPiece raw_sets) {
+FirstPartySetParser::ParseSetsFromComponentUpdater(base::StringPiece raw_sets) {
   absl::optional<base::Value> maybe_value = base::JSONReader::Read(
       raw_sets, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS);
   if (!maybe_value.has_value())
@@ -139,7 +138,7 @@
       base::flat_map<net::SchemefulSite, net::SchemefulSite>>();
   base::flat_set<net::SchemefulSite> elements;
   for (const auto& value : maybe_value->GetList()) {
-    if (!ParsePreloadedSet(value, *map, elements))
+    if (!ParseSet(value, *map, elements))
       return nullptr;
   }
 
diff --git a/services/network/first_party_sets/first_party_set_parser.h b/services/network/first_party_sets/first_party_set_parser.h
index c65a63b..4a332e62 100644
--- a/services/network/first_party_sets/first_party_set_parser.h
+++ b/services/network/first_party_sets/first_party_set_parser.h
@@ -32,11 +32,11 @@
   // representation of a list of set declarations according to the format
   // specified in this document: https://github.com/privacycg/first-party-sets.
   // This function does not check versions or assertions, since it is intended
-  // only for *preloaded* sets.
+  // only for sets received by Component Updater.
   //
   // Returns nullptr if parsing or validation of any set failed.
   static std::unique_ptr<base::flat_map<net::SchemefulSite, net::SchemefulSite>>
-  ParsePreloadedSets(base::StringPiece raw_sets);
+  ParseSetsFromComponentUpdater(base::StringPiece raw_sets);
 
   // Canonicalizes the passed in origin to a registered domain. In particular,
   // this ensures that the origin is non-opaque, is HTTPS, and has a registered
diff --git a/services/network/first_party_sets/first_party_set_parser_unittest.cc b/services/network/first_party_sets/first_party_set_parser_unittest.cc
index 1b80e1c3..485890b 100644
--- a/services/network/first_party_sets/first_party_set_parser_unittest.cc
+++ b/services/network/first_party_sets/first_party_set_parser_unittest.cc
@@ -22,15 +22,15 @@
   return testing::ExplainMatchResult(testing::Eq(want), got, result_listener);
 }
 
-TEST(FirstPartySetParser_Preloaded, RejectsEmpty) {
+TEST(FirstPartySetParser, RejectsEmpty) {
   // If the input isn't valid JSON, we should
   // reject it. In particular, we should reject
   // empty input.
 
-  EXPECT_FALSE(FirstPartySetParser::ParsePreloadedSets(""));
+  EXPECT_FALSE(FirstPartySetParser::ParseSetsFromComponentUpdater(""));
 }
 
-TEST(FirstPartySetParser_Preloaded, RejectsNonemptyMalformed) {
+TEST(FirstPartySetParser, RejectsNonemptyMalformed) {
   // If the input isn't valid JSON, we should
   // reject it.
   const char input[] = "certainly not valid JSON";
@@ -38,7 +38,7 @@
   // Sanity check that the input is not valid JSON.
   ASSERT_FALSE(base::JSONReader::Read(input));
 
-  EXPECT_FALSE(FirstPartySetParser::ParsePreloadedSets(input));
+  EXPECT_FALSE(FirstPartySetParser::ParseSetsFromComponentUpdater(input));
 }
 
 TEST(FirstPartySetParser, RejectsNonListInput) {
@@ -46,7 +46,7 @@
   const std::string input = "{}";
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_FALSE(FirstPartySetParser::ParsePreloadedSets(input));
+  EXPECT_FALSE(FirstPartySetParser::ParseSetsFromComponentUpdater(input));
 }
 
 TEST(FirstPartySetParser, AcceptsTrivial) {
@@ -55,7 +55,7 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
               Pointee(IsEmpty()));
 }
 
@@ -69,7 +69,7 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_FALSE(FirstPartySetParser::ParsePreloadedSets(input));
+  EXPECT_FALSE(FirstPartySetParser::ParseSetsFromComponentUpdater(input));
 }
 
 TEST(FirstPartySetParser, AcceptsMinimal) {
@@ -82,7 +82,7 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
               Pointee(UnorderedElementsAre(
                   Pair(SerializesTo("https://example.test"),
                        SerializesTo("https://example.test")),
@@ -96,7 +96,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsTypeUnsafeOwner) {
@@ -106,7 +107,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsNonHTTPSOwner) {
@@ -119,7 +121,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsNonOriginOwner) {
@@ -132,7 +135,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsOwnerWithoutRegisteredDomain) {
@@ -145,7 +149,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsMissingMembers) {
@@ -154,7 +159,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsTypeUnsafeMembers) {
@@ -167,7 +173,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsNonHTTPSMember) {
@@ -180,7 +187,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsNonOriginMember) {
@@ -193,7 +201,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsMemberWithoutRegisteredDomain) {
@@ -206,7 +215,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, TruncatesSubdomain_Owner) {
@@ -219,7 +229,7 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
               Pointee(UnorderedElementsAre(
                   Pair(SerializesTo("https://example.test"),
                        SerializesTo("https://example.test")),
@@ -237,7 +247,7 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
               Pointee(UnorderedElementsAre(
                   Pair(SerializesTo("https://example.test"),
                        SerializesTo("https://example.test")),
@@ -263,7 +273,7 @@
   ASSERT_TRUE(base::JSONReader::Read(input));
 
   EXPECT_THAT(
-      FirstPartySetParser::ParsePreloadedSets(input),
+      FirstPartySetParser::ParseSetsFromComponentUpdater(input),
       Pointee(UnorderedElementsAre(Pair(SerializesTo("https://example.test"),
                                         SerializesTo("https://example.test")),
                                    Pair(SerializesTo("https://member1.test"),
@@ -291,7 +301,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, RejectsInvalidSets_InvalidMember) {
@@ -311,7 +322,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, AllowsTrailingCommas) {
@@ -328,7 +340,7 @@
   ASSERT_TRUE(base::JSONReader::Read(
       input, base::JSONParserOptions::JSON_ALLOW_TRAILING_COMMAS));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input),
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
               Pointee(UnorderedElementsAre(
                   Pair(SerializesTo("https://example.test"),
                        SerializesTo("https://example.test")),
@@ -353,7 +365,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, Rejects_MemberAsOwner) {
@@ -373,7 +386,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, Rejects_SameMember) {
@@ -393,7 +407,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 TEST(FirstPartySetParser, Rejects_OwnerAsMember) {
@@ -413,7 +428,8 @@
   // Sanity check that the input is actually valid JSON.
   ASSERT_TRUE(base::JSONReader::Read(input));
 
-  EXPECT_THAT(FirstPartySetParser::ParsePreloadedSets(input), IsNull());
+  EXPECT_THAT(FirstPartySetParser::ParseSetsFromComponentUpdater(input),
+              IsNull());
 }
 
 }  // namespace network
diff --git a/services/network/first_party_sets/first_party_sets.cc b/services/network/first_party_sets/first_party_sets.cc
index 8e9ed89..796d2e68 100644
--- a/services/network/first_party_sets/first_party_sets.cc
+++ b/services/network/first_party_sets/first_party_sets.cc
@@ -69,7 +69,7 @@
 base::flat_map<net::SchemefulSite, net::SchemefulSite>*
 FirstPartySets::ParseAndSet(base::StringPiece raw_sets) {
   std::unique_ptr<base::flat_map<net::SchemefulSite, net::SchemefulSite>>
-      parsed = FirstPartySetParser::ParsePreloadedSets(raw_sets);
+      parsed = FirstPartySetParser::ParseSetsFromComponentUpdater(raw_sets);
   if (parsed) {
     sets_.swap(*parsed);
   } else {
diff --git a/services/network/first_party_sets/test/first_party_set_parser_fuzzer.cc b/services/network/first_party_sets/test/first_party_set_parser_fuzzer.cc
index 7c4c2c7..8824918 100644
--- a/services/network/first_party_sets/test/first_party_set_parser_fuzzer.cc
+++ b/services/network/first_party_sets/test/first_party_set_parser_fuzzer.cc
@@ -13,7 +13,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   base::StringPiece string_input(reinterpret_cast<const char*>(data), size);
-  FirstPartySetParser::ParsePreloadedSets(string_input);
+  FirstPartySetParser::ParseSetsFromComponentUpdater(string_input);
   return 0;
 }
 
diff --git a/services/network/first_party_sets/test/first_party_set_parser_json_fuzzer.cc b/services/network/first_party_sets/test/first_party_set_parser_json_fuzzer.cc
index a1927db..807212db 100644
--- a/services/network/first_party_sets/test/first_party_set_parser_json_fuzzer.cc
+++ b/services/network/first_party_sets/test/first_party_set_parser_json_fuzzer.cc
@@ -19,5 +19,5 @@
   if (getenv("LPM_DUMP_NATIVE_INPUT"))
     std::cout << native_input << std::endl;
 
-  network::FirstPartySetParser::ParsePreloadedSets(native_input);
+  network::FirstPartySetParser::ParseSetsFromComponentUpdater(native_input);
 }
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 9cdf5d5..e606e81f 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -468,11 +468,11 @@
           std::make_unique<NetworkContextApplicationStatusListener>()),
 #endif
       receiver_(this, std::move(receiver)),
-      cookie_manager_(std::make_unique<CookieManager>(
-          url_request_context,
-          nullptr,
-          nullptr /* preloaded_first_party_sets */,
-          nullptr)),
+      cookie_manager_(
+          std::make_unique<CookieManager>(url_request_context,
+                                          nullptr,
+                                          nullptr /* first_party_sets */,
+                                          nullptr)),
       socket_factory_(
           std::make_unique<SocketFactory>(url_request_context_->net_log(),
                                           url_request_context)),
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index 02c8af43..65ac4fb 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -735,7 +735,7 @@
   }
 }
 
-void NetworkService::SetPreloadedFirstPartySets(const std::string& raw_sets) {
+void NetworkService::SetFirstPartySets(const std::string& raw_sets) {
   first_party_sets_->ParseAndSet(raw_sets);
 }
 
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 26ddd61..3342648 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -191,7 +191,7 @@
 #endif
   void BindTestInterface(
       mojo::PendingReceiver<mojom::NetworkServiceTest> receiver) override;
-  void SetPreloadedFirstPartySets(const std::string& raw_sets) override;
+  void SetFirstPartySets(const std::string& raw_sets) override;
   void SetExplicitlyAllowedPorts(const std::vector<uint16_t>& ports) override;
 
   // Returns an HttpAuthHandlerFactory for the given NetworkContext.
diff --git a/services/network/public/DIR_METADATA b/services/network/public/DIR_METADATA
deleted file mode 100644
index 1fd3fb96..0000000
--- a/services/network/public/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Services>Network"
-}
\ No newline at end of file
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 3a1abc4..8752c4b 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -341,16 +341,14 @@
   // environments.
   BindTestInterface(pending_receiver<NetworkServiceTest> receiver);
 
-  // Sets the preloaded First-Party Sets data. |raw_sets| is the JSON-encoded
+  // Sets the First-Party Sets data. |raw_sets| is the JSON-encoded
   // string representation of a collection of set declarations according to the
   // format specified in this document:
   // https://github.com/privacycg/first-party-sets
-  // Note that by setting the preloaded First-Party Sets, any previous notion of
-  // preloaded First-Party Sets is cleared. This method can be partially
-  // successful in the event of malformed input (which also clears previously-
-  // known First-Party Sets), but does nothing if given non-JSON input or JSON
-  // which is not a dictionary.
-  SetPreloadedFirstPartySets(string raw_sets);
+  // Note that by setting the First-Party Sets, any previous notion of
+  // First-Party Sets is cleared. On any kind of error, all First-Party Sets are
+  // cleared (except for the manually-specified set, if one exists).
+  SetFirstPartySets(string raw_sets);
 
   // Sets the list of ports which will be permitted even if they normally would
   // be restricted.
diff --git a/services/network/public/mojom/url_response_head.mojom b/services/network/public/mojom/url_response_head.mojom
index 8a27705..13401eb 100644
--- a/services/network/public/mojom/url_response_head.mojom
+++ b/services/network/public/mojom/url_response_head.mojom
@@ -91,6 +91,10 @@
   // Remote address of the socket which fetched this resource.
   IPEndPoint remote_endpoint;
 
+  // True if the response was fetched from the cache and validated over the
+  // network.
+  bool is_validated = false;
+
   // True if the response came from cache.
   bool was_fetched_via_cache = false;
 
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index cac86e5ec..b898da1 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -114,6 +114,8 @@
   response->connection_info = response_info.connection_info;
   response->remote_endpoint = response_info.remote_endpoint;
   response->was_fetched_via_cache = request->was_cached();
+  response->is_validated = (response_info.cache_entry_status ==
+                            net::HttpResponseInfo::ENTRY_VALIDATED);
   response->proxy_server = request->proxy_server();
   response->network_accessed = response_info.network_accessed;
   response->async_revalidation_requested =
diff --git a/services/network/web_bundle_manager.cc b/services/network/web_bundle_manager.cc
index 49a6738..88d8c148 100644
--- a/services/network/web_bundle_manager.cc
+++ b/services/network/web_bundle_manager.cc
@@ -90,7 +90,9 @@
     const GURL& bundle_url,
     const ResourceRequest::WebBundleTokenParams& web_bundle_token_params,
     int32_t process_id,
-    const absl::optional<url::Origin>& request_initiator_origin_lock) {
+    const absl::optional<url::Origin>& request_initiator_origin_lock,
+    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+    absl::optional<std::string> devtools_request_id) {
   DCHECK(factories_.find({process_id, web_bundle_token_params.token}) ==
          factories_.end());
 
@@ -108,7 +110,8 @@
   auto factory = std::make_unique<WebBundleURLLoaderFactory>(
       bundle_url, std::move(remote), request_initiator_origin_lock,
       std::make_unique<MemoryQuotaConsumer>(weak_ptr_factory_.GetWeakPtr(),
-                                            process_id));
+                                            process_id),
+      std::move(devtools_observer), std::move(devtools_request_id));
 
   // Process pending subresource requests if there are.
   // These subresource requests arrived earlier than the request for the bundle.
diff --git a/services/network/web_bundle_manager.h b/services/network/web_bundle_manager.h
index 323cc010..9f1bac8 100644
--- a/services/network/web_bundle_manager.h
+++ b/services/network/web_bundle_manager.h
@@ -35,7 +35,9 @@
       const GURL& bundle_url,
       const ResourceRequest::WebBundleTokenParams& params,
       int32_t process_id,
-      const absl::optional<url::Origin>& request_initiator_origin_lock);
+      const absl::optional<url::Origin>& request_initiator_origin_lock,
+      mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+      absl::optional<std::string> devtools_request_id);
 
   void StartSubresourceRequest(
       mojo::PendingReceiver<mojom::URLLoader> receiver,
diff --git a/services/network/web_bundle_manager_unittest.cc b/services/network/web_bundle_manager_unittest.cc
index 5cc1ebe..af56e5c 100644
--- a/services/network/web_bundle_manager_unittest.cc
+++ b/services/network/web_bundle_manager_unittest.cc
@@ -99,7 +99,9 @@
   base::WeakPtr<WebBundleURLLoaderFactory> factory =
       manager.CreateWebBundleURLLoaderFactory(
           GURL(kBundleUrl), create_params, process_id,
-          /*request_initiator_origin_lock=*/absl::nullopt);
+          /*request_initiator_origin_lock=*/absl::nullopt,
+          /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+          /*devtools_request_id=*/absl::nullopt);
 
   return std::forward_as_tuple(std::move(factory), std::move(handle));
 }
@@ -165,7 +167,9 @@
 
   auto factory = manager.CreateWebBundleURLLoaderFactory(
       GURL(kBundleUrl), create_params, process_id1,
-      /*request_initiator_origin_lock=*/absl::nullopt);
+      /*request_initiator_origin_lock=*/absl::nullopt,
+      /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+      /*devtools_request_id=*/absl::nullopt);
   ASSERT_TRUE(factory);
 
   ResourceRequest::WebBundleTokenParams find_params(GURL(kBundleUrl), token,
@@ -185,7 +189,9 @@
 
   auto factory = manager.CreateWebBundleURLLoaderFactory(
       GURL(kBundleUrl), create_params, process_id1,
-      /*request_initiator_origin_lock=*/absl::nullopt);
+      /*request_initiator_origin_lock=*/absl::nullopt,
+      /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+      /*devtools_request_id=*/absl::nullopt);
   ASSERT_TRUE(factory);
 
   ResourceRequest::WebBundleTokenParams find_params1(GURL(kBundleUrl), token,
@@ -214,7 +220,9 @@
 
     auto factory = manager.CreateWebBundleURLLoaderFactory(
         GURL(kBundleUrl), create_params, process_id1,
-        /*request_initiator_origin_lock=*/absl::nullopt);
+        /*request_initiator_origin_lock=*/absl::nullopt,
+        /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+        /*devtools_request_id=*/absl::nullopt);
     ASSERT_TRUE(factory);
     ASSERT_TRUE(
         GetWebBundleURLLoaderFactory(manager, find_params, process_id1));
@@ -283,7 +291,9 @@
 
   auto factory = manager.CreateWebBundleURLLoaderFactory(
       GURL(kBundleUrl), token_params, process_id1,
-      /*request_initiator_origin_lock=*/absl::nullopt);
+      /*request_initiator_origin_lock=*/absl::nullopt,
+      /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+      /*devtools_request_id=*/absl::nullopt);
 
   // Then, simulate that the bundle is loaded from the network, calling
   // SetBundleStream manually.
diff --git a/services/network/web_bundle_url_loader_factory.cc b/services/network/web_bundle_url_loader_factory.cc
index 751d09b..fe84274 100644
--- a/services/network/web_bundle_url_loader_factory.cc
+++ b/services/network/web_bundle_url_loader_factory.cc
@@ -453,12 +453,16 @@
     mojo::Remote<mojom::WebBundleHandle> web_bundle_handle,
     const absl::optional<url::Origin>& request_initiator_origin_lock,
     std::unique_ptr<WebBundleMemoryQuotaConsumer>
-        web_bundle_memory_quota_consumer)
+        web_bundle_memory_quota_consumer,
+    mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+    absl::optional<std::string> devtools_request_id)
     : bundle_url_(bundle_url),
       web_bundle_handle_(std::move(web_bundle_handle)),
       request_initiator_origin_lock_(request_initiator_origin_lock),
       web_bundle_memory_quota_consumer_(
-          std::move(web_bundle_memory_quota_consumer)) {}
+          std::move(web_bundle_memory_quota_consumer)),
+      devtools_observer_(std::move(devtools_observer)),
+      devtools_request_id_(std::move(devtools_request_id)) {}
 
 WebBundleURLLoaderFactory::~WebBundleURLLoaderFactory() {
   for (auto loader : pending_loaders_) {
diff --git a/services/network/web_bundle_url_loader_factory.h b/services/network/web_bundle_url_loader_factory.h
index 4877930..1144261 100644
--- a/services/network/web_bundle_url_loader_factory.h
+++ b/services/network/web_bundle_url_loader_factory.h
@@ -34,7 +34,9 @@
       mojo::Remote<mojom::WebBundleHandle> web_bundle_handle,
       const absl::optional<url::Origin>& request_initiator_origin_lock,
       std::unique_ptr<WebBundleMemoryQuotaConsumer>
-          web_bundle_memory_quota_consumer);
+          web_bundle_memory_quota_consumer,
+      mojo::PendingRemote<mojom::DevToolsObserver> devtools_observer,
+      absl::optional<std::string> devtools_request_id);
   ~WebBundleURLLoaderFactory();
   WebBundleURLLoaderFactory(const WebBundleURLLoaderFactory&) = delete;
   WebBundleURLLoaderFactory& operator=(const WebBundleURLLoaderFactory&) =
@@ -97,6 +99,8 @@
   const absl::optional<::url::Origin> request_initiator_origin_lock_;
   std::unique_ptr<WebBundleMemoryQuotaConsumer>
       web_bundle_memory_quota_consumer_;
+  mojo::Remote<mojom::DevToolsObserver> devtools_observer_;
+  absl::optional<std::string> devtools_request_id_;
   std::unique_ptr<BundleDataSource> source_;
   mojo::Remote<web_package::mojom::WebBundleParser> parser_;
   web_package::mojom::BundleMetadataPtr metadata_;
diff --git a/services/network/web_bundle_url_loader_factory_unittest.cc b/services/network/web_bundle_url_loader_factory_unittest.cc
index d3b6f368..9aeea80 100644
--- a/services/network/web_bundle_url_loader_factory_unittest.cc
+++ b/services/network/web_bundle_url_loader_factory_unittest.cc
@@ -160,7 +160,9 @@
     factory_ = std::make_unique<WebBundleURLLoaderFactory>(
         GURL(kBundleUrl), std::move(handle),
         /*request_initiator_origin_lock=*/absl::nullopt,
-        std::make_unique<MockMemoryQuotaConsumer>());
+        std::make_unique<MockMemoryQuotaConsumer>(),
+        /*devtools_observer=*/mojo::PendingRemote<mojom::DevToolsObserver>(),
+        /*devtools_request_id=*/absl::nullopt);
     factory_->SetBundleStream(std::move(consumer));
   }
 
diff --git a/services/preferences/public/cpp/dictionary_value_update.cc b/services/preferences/public/cpp/dictionary_value_update.cc
index 7d7efe2..30d1b8e 100644
--- a/services/preferences/public/cpp/dictionary_value_update.cc
+++ b/services/preferences/public/cpp/dictionary_value_update.cc
@@ -115,7 +115,7 @@
     return;
   }
   RecordKey(key);
-  value_->SetWithoutPathExpansion(key, std::move(in_value));
+  value_->SetKey(key, base::Value::FromUniquePtrValue(std::move(in_value)));
 }
 
 std::unique_ptr<DictionaryValueUpdate>
@@ -123,8 +123,8 @@
     base::StringPiece path,
     std::unique_ptr<base::DictionaryValue> in_value) {
   RecordKey(path);
-  auto* dictionary_value = static_cast<base::DictionaryValue*>(
-      value_->SetWithoutPathExpansion(path, std::move(in_value)));
+  auto* dictionary_value = static_cast<base::DictionaryValue*>(value_->SetKey(
+      path, base::Value::FromUniquePtrValue(std::move(in_value))));
 
   std::vector<std::string> full_path = path_;
   full_path.push_back(std::string(path));
diff --git a/services/preferences/tracked/pref_hash_filter.cc b/services/preferences/tracked/pref_hash_filter.cc
index 9201c65..c9ced554 100644
--- a/services/preferences/tracked/pref_hash_filter.cc
+++ b/services/preferences/tracked/pref_hash_filter.cc
@@ -346,10 +346,11 @@
       case TrackedPreferenceType::SPLIT: {
         const base::DictionaryValue* dict_value = nullptr;
         pref_store_contents->GetDictionary(changed_path, &dict_value);
-        changed_paths_macs->SetWithoutPathExpansion(
+        changed_paths_macs->SetKey(
             changed_path,
-            external_validation_hash_store_pair_->first->ComputeSplitMacs(
-                changed_path, dict_value));
+            base::Value::FromUniquePtrValue(
+                external_validation_hash_store_pair_->first->ComputeSplitMacs(
+                    changed_path, dict_value)));
         break;
       }
     }
diff --git a/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h b/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
index 5e127412..3d3c68a8 100644
--- a/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/returned_resource_mojom_traits.h
@@ -25,6 +25,11 @@
     return resource.sync_token;
   }
 
+  static gfx::GpuFenceHandle release_fence(
+      const viz::ReturnedResource& resource) {
+    return resource.release_fence.Clone();
+  }
+
   static int32_t count(const viz::ReturnedResource& resource) {
     return resource.count;
   }
@@ -35,7 +40,8 @@
 
   static bool Read(viz::mojom::ReturnedResourceDataView data,
                    viz::ReturnedResource* out) {
-    if (!data.ReadSyncToken(&out->sync_token) || !data.ReadId(&out->id)) {
+    if (!data.ReadSyncToken(&out->sync_token) ||
+        !data.ReadReleaseFence(&out->release_fence) || !data.ReadId(&out->id)) {
       return false;
     }
     out->count = data.count();
diff --git a/services/viz/public/mojom/compositing/returned_resource.mojom b/services/viz/public/mojom/compositing/returned_resource.mojom
index 1251336..fe32f00 100644
--- a/services/viz/public/mojom/compositing/returned_resource.mojom
+++ b/services/viz/public/mojom/compositing/returned_resource.mojom
@@ -6,11 +6,13 @@
 
 import "gpu/ipc/common/sync_token.mojom";
 import "services/viz/public/mojom/compositing/resource_id.mojom";
+import "ui/gfx/mojom/gpu_fence_handle.mojom";
 
 // See components/viz/common/resources/returned_resource.h.
 struct ReturnedResource {
   ResourceId id;
   gpu.mojom.SyncToken sync_token;
+  gfx.mojom.GpuFenceHandle? release_fence;
   int32 count;
   bool lost;
 };
diff --git a/storage/browser/blob/DIR_METADATA b/storage/browser/blob/DIR_METADATA
index 433b3a9..19266882 100644
--- a/storage/browser/blob/DIR_METADATA
+++ b/storage/browser/blob/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>FileAPI"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/storage/browser/database/DIR_METADATA b/storage/browser/database/DIR_METADATA
index f337a38..67bdd01 100644
--- a/storage/browser/database/DIR_METADATA
+++ b/storage/browser/database/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>WebSQL"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/storage/browser/file_system/DIR_METADATA b/storage/browser/file_system/DIR_METADATA
index e704db9..a32478d 100644
--- a/storage/browser/file_system/DIR_METADATA
+++ b/storage/browser/file_system/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>FileSystem"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/storage/browser/quota/DIR_METADATA b/storage/browser/quota/DIR_METADATA
index c03de17..58c664b 100644
--- a/storage/browser/quota/DIR_METADATA
+++ b/storage/browser/quota/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>Quota"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/storage/common/database/DIR_METADATA b/storage/common/database/DIR_METADATA
index f337a38..67bdd01 100644
--- a/storage/common/database/DIR_METADATA
+++ b/storage/common/database/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>WebSQL"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/storage/common/file_system/DIR_METADATA b/storage/common/file_system/DIR_METADATA
index e704db9..a32478d 100644
--- a/storage/common/file_system/DIR_METADATA
+++ b/storage/common/file_system/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Blink>Storage>FileSystem"
 }
-team_email: "storage-dev@chromium.org"
\ No newline at end of file
diff --git a/testing/buildbot/DIR_METADATA b/testing/buildbot/DIR_METADATA
index d2d9af5..3a18da1e 100644
--- a/testing/buildbot/DIR_METADATA
+++ b/testing/buildbot/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Infra>Client>Chrome"
 }
-team_email: "infra-dev@chromium.org"
\ No newline at end of file
diff --git a/testing/buildbot/filters/DIR_METADATA b/testing/buildbot/filters/DIR_METADATA
deleted file mode 100644
index d2d9af5..0000000
--- a/testing/buildbot/filters/DIR_METADATA
+++ /dev/null
@@ -1,12 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Infra>Client>Chrome"
-}
-team_email: "infra-dev@chromium.org"
\ No newline at end of file
diff --git a/testing/scripts/DIR_METADATA b/testing/scripts/DIR_METADATA
index d2d9af5..3a18da1e 100644
--- a/testing/scripts/DIR_METADATA
+++ b/testing/scripts/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "Infra>Client>Chrome"
 }
-team_email: "infra-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/android_deps/libs/DIR_METADATA b/third_party/android_deps/libs/DIR_METADATA
deleted file mode 100644
index 7a2580a..0000000
--- a/third_party/android_deps/libs/DIR_METADATA
+++ /dev/null
@@ -1 +0,0 @@
-os: ANDROID
diff --git a/third_party/android_swipe_refresh/java/DIR_METADATA b/third_party/android_swipe_refresh/java/DIR_METADATA
index 3052711..1744a1f 100644
--- a/third_party/android_swipe_refresh/java/DIR_METADATA
+++ b/third_party/android_swipe_refresh/java/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "UI>Browser>Mobile"
-}
 
 os: ANDROID
diff --git a/third_party/blink/common/DIR_METADATA b/third_party/blink/common/DIR_METADATA
deleted file mode 100644
index bcfcab4..0000000
--- a/third_party/blink/common/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "Blink"
-}
diff --git a/third_party/blink/public/common/DIR_METADATA b/third_party/blink/public/common/DIR_METADATA
deleted file mode 100644
index 90b2e9c..0000000
--- a/third_party/blink/public/common/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>Internals>Modularization"
-}
-
-team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/blink/public/common/messaging/DIR_METADATA b/third_party/blink/public/common/messaging/DIR_METADATA
index 169c29b..b431244 100644
--- a/third_party/blink/public/common/messaging/DIR_METADATA
+++ b/third_party/blink/public/common/messaging/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Messaging"
 }
 
-team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/array_buffer/DIR_METADATA b/third_party/blink/public/mojom/array_buffer/DIR_METADATA
index 169c29b..b431244 100644
--- a/third_party/blink/public/mojom/array_buffer/DIR_METADATA
+++ b/third_party/blink/public/mojom/array_buffer/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Messaging"
 }
 
-team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/messaging/DIR_METADATA b/third_party/blink/public/mojom/messaging/DIR_METADATA
index 169c29b..b431244 100644
--- a/third_party/blink/public/mojom/messaging/DIR_METADATA
+++ b/third_party/blink/public/mojom/messaging/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Messaging"
 }
 
-team_email: "platform-architecture-dev@chromium.org"
diff --git a/third_party/blink/public/mojom/timing/resource_timing.mojom b/third_party/blink/public/mojom/timing/resource_timing.mojom
index a20d349..65dddd4a 100644
--- a/third_party/blink/public/mojom/timing/resource_timing.mojom
+++ b/third_party/blink/public/mojom/timing/resource_timing.mojom
@@ -31,6 +31,13 @@
   string description;
 };
 
+// https://fetch.spec.whatwg.org/#concept-response-cache-state
+enum CacheState {
+  kNone,
+  kLocal,
+  kValidated,
+};
+
 // This struct holds the information from PerformanceResourceTiming that needs
 // to be passed between processes. This is currently used to send timing
 // information about cross-process iframes for window.performance.
@@ -72,9 +79,8 @@
   RequestContextType context_type;
   network.mojom.RequestDestination request_destination;
 
-  // Corresponds to |transferSize| in PerformanceResourceTiming
-  // (http://www.w3.org/TR/resource-timing-2/).
-  uint64 transfer_size;
+  // https://w3c.github.io/resource-timing/#dfn-cache-mode
+  CacheState cache_state;
 
   // Corresponds to |encodedBodySize| in PerformanceResourceTiming
   // (http://www.w3.org/TR/resource-timing-2/).
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index f9327f92..9fbaa772 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3224,6 +3224,9 @@
   kRTCOfferAnswerOptionsVoiceActivityDetection = 3909,
   kMultiColAndListItem = 3910,
   kCaptureHandle = 3911,
+  kSVGText = 3912,
+  kGetBBoxForText = 3913,
+  kSVGTextHangingFromPath = 3914,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_url_response.h b/third_party/blink/public/platform/web_url_response.h
index eea8e46..f650a0b 100644
--- a/third_party/blink/public/platform/web_url_response.h
+++ b/third_party/blink/public/platform/web_url_response.h
@@ -319,6 +319,9 @@
   BLINK_PLATFORM_EXPORT void SetConnectionInfo(
       net::HttpResponseInfo::ConnectionInfo);
 
+  // Whether the response was cached and validated over the network.
+  BLINK_PLATFORM_EXPORT void SetIsValidated(bool);
+
   // Original size of the response before decompression.
   BLINK_PLATFORM_EXPORT void SetEncodedDataLength(int64_t);
 
diff --git a/third_party/blink/renderer/bindings/core/v8/DIR_METADATA b/third_party/blink/renderer/bindings/core/v8/DIR_METADATA
deleted file mode 100644
index 9eb47abd..0000000
--- a/third_party/blink/renderer/bindings/core/v8/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>Bindings"
-}
-
-team_email: "blink-reviews-bindings@chromium.org"
diff --git a/third_party/blink/renderer/bindings/generated_in_core.gni b/third_party/blink/renderer/bindings/generated_in_core.gni
index 6ee5113..f9a2532 100644
--- a/third_party/blink/renderer/bindings/generated_in_core.gni
+++ b/third_party/blink/renderer/bindings/generated_in_core.gni
@@ -115,8 +115,6 @@
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_custom_layout_constraints_options.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline_options.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_timeline_options.h",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.cc",
-  "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_document_transition_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_2d_init.cc",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_2d_init.h",
   "$root_gen_dir/third_party/blink/renderer/bindings/core/v8/v8_dom_matrix_init.cc",
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
index cdc8827..d1ffb12 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/union.py
@@ -467,6 +467,7 @@
     assert isinstance(cg_context, CodeGenContext)
 
     decls = ListNode()
+    defs = ListNode()
 
     for member in cg_context.union_members:
         if member.is_null:
@@ -479,7 +480,49 @@
                                               member.content_type()),
                                       ])
             decls.append(func_def)
-        if not member.is_null:
+        elif member.type_info.is_move_effective:
+            func_decl = CxxFuncDeclNode(
+                name=cg_context.class_name,
+                arg_decls=["{} value".format(member.type_info.member_ref_t)],
+                return_type="",
+                explicit=True)
+            func_def = CxxFuncDefNode(
+                name=cg_context.class_name,
+                arg_decls=["{} value".format(member.type_info.member_ref_t)],
+                return_type="",
+                class_name=cg_context.class_name,
+                member_initializer_list=[
+                    "content_type_({})".format(member.content_type()),
+                    "{}(value)".format(member.var_name),
+                ])
+            func_def.set_base_template_vars(cg_context.template_bindings())
+            func_def.body.append(
+                make_check_assignment_value(cg_context, member, "value"))
+            decls.append(func_decl)
+            defs.append(func_def)
+            defs.append(EmptyNode())
+
+            func_decl = CxxFuncDeclNode(
+                name=cg_context.class_name,
+                arg_decls=["{}&& value".format(member.type_info.value_t)],
+                return_type="",
+                explicit=True)
+            func_def = CxxFuncDefNode(
+                name=cg_context.class_name,
+                arg_decls=["{}&& value".format(member.type_info.value_t)],
+                return_type="",
+                class_name=cg_context.class_name,
+                member_initializer_list=[
+                    "content_type_({})".format(member.content_type()),
+                    "{}(std::move(value))".format(member.var_name),
+                ])
+            func_def.set_base_template_vars(cg_context.template_bindings())
+            func_def.body.append(
+                make_check_assignment_value(cg_context, member, "value"))
+            decls.append(func_decl)
+            defs.append(func_def)
+            defs.append(EmptyNode())
+        else:
             func_def = CxxFuncDefNode(
                 name=cg_context.class_name,
                 arg_decls=["{} value".format(member.type_info.member_ref_t)],
@@ -492,21 +535,8 @@
             func_def.body.append(
                 make_check_assignment_value(cg_context, member, "value"))
             decls.append(func_def)
-        if not member.is_null and member.type_info.is_move_effective:
-            func_def = CxxFuncDefNode(
-                name=cg_context.class_name,
-                arg_decls=["{}&& value".format(member.type_info.value_t)],
-                return_type="",
-                explicit=True,
-                member_initializer_list=[
-                    "content_type_({})".format(member.content_type()),
-                    "{}(std::move(value))".format(member.var_name),
-                ])
-            func_def.body.append(
-                make_check_assignment_value(cg_context, member, "value"))
-            decls.append(func_def)
 
-    return decls, None
+    return decls, defs
 
 
 def make_accessor_functions(cg_context):
@@ -518,6 +548,11 @@
     decls = ListNode()
     defs = ListNode()
 
+    def add(func_decl, func_def):
+        decls.append(func_decl)
+        defs.append(func_def)
+        defs.append(EmptyNode())
+
     func_def = CxxFuncDefNode(name="GetContentType",
                               arg_decls=[],
                               return_type="ContentType",
@@ -538,7 +573,7 @@
         func_def.set_base_template_vars(cg_context.template_bindings())
         func_def.body.append(
             F("return content_type_ == {};", member.content_type()))
-        return func_def
+        return func_def, None
 
     def make_api_get(member):
         func_def = CxxFuncDefNode(name=member.api_get,
@@ -550,7 +585,7 @@
             F("DCHECK_EQ(content_type_, {});", member.content_type()),
             F("return {};", member.var_name),
         ])
-        return func_def
+        return func_def, None
 
     def make_api_set(member):
         func_def = CxxFuncDefNode(
@@ -564,24 +599,46 @@
             F("{} = value;", member.var_name),
             F("content_type_ = {};", member.content_type()),
         ])
+        return func_def, None
 
-        if not member.type_info.is_move_effective:
-            return func_def
+    def make_api_set_copy_and_move(member):
+        copy_func_decl = CxxFuncDeclNode(
+            name=member.api_set,
+            arg_decls=["{} value".format(member.type_info.member_ref_t)],
+            return_type="void")
+        copy_func_def = CxxFuncDefNode(
+            name=member.api_set,
+            arg_decls=["{} value".format(member.type_info.member_ref_t)],
+            return_type="void",
+            class_name=cg_context.class_name)
+        copy_func_def.set_base_template_vars(cg_context.template_bindings())
+        copy_func_def.body.extend([
+            make_check_assignment_value(cg_context, member, "value"),
+            T("Clear();"),
+            F("{} = value;", member.var_name),
+            F("content_type_ = {};", member.content_type()),
+        ])
 
-        decls = ListNode([func_def])
-        func_def = CxxFuncDefNode(
+        move_func_decl = CxxFuncDeclNode(
             name=member.api_set,
             arg_decls=["{}&& value".format(member.type_info.value_t)],
             return_type="void")
-        func_def.set_base_template_vars(cg_context.template_bindings())
-        func_def.body.extend([
+        move_func_def = CxxFuncDefNode(
+            name=member.api_set,
+            arg_decls=["{}&& value".format(member.type_info.value_t)],
+            return_type="void",
+            class_name=cg_context.class_name)
+        move_func_def.set_base_template_vars(cg_context.template_bindings())
+        move_func_def.body.extend([
             make_check_assignment_value(cg_context, member, "value"),
             T("Clear();"),
             F("{} = std::move(value);", member.var_name),
             F("content_type_ = {};", member.content_type()),
         ])
-        decls.append(func_def)
-        return decls
+
+        decls = ListNode([copy_func_decl, move_func_decl])
+        defs = ListNode([copy_func_def, EmptyNode(), move_func_def])
+        return decls, defs
 
     def make_api_set_null(member):
         func_def = CxxFuncDefNode(name=member.api_set,
@@ -592,20 +649,23 @@
             T("Clear();"),
             F("content_type_ = {};", member.content_type()),
         ])
-        return func_def
+        return func_def, None
 
     for member in cg_context.union_members:
         if member.is_null:
-            decls.append(make_api_pred(member))
-            decls.append(make_api_set_null(member))
+            add(*make_api_pred(member))
+            add(*make_api_set_null(member))
         else:
-            decls.append(make_api_pred(member))
+            add(*make_api_pred(member))
             for alias in member.typedef_aliases:
-                decls.append(make_api_pred(alias))
-            decls.append(make_api_get(member))
+                add(*make_api_pred(alias))
+            add(*make_api_get(member))
             for alias in member.typedef_aliases:
-                decls.append(make_api_get(alias))
-            decls.append(make_api_set(member))
+                add(*make_api_get(alias))
+            if member.type_info.is_move_effective:
+                add(*make_api_set_copy_and_move(member))
+            else:
+                add(*make_api_set(member))
         decls.append(EmptyNode())
 
     def make_api_subunion_pred(subunion, subunion_members):
@@ -667,19 +727,9 @@
     for subunion in cg_context.union.union_members:
         subunion_members = create_union_members(subunion)
         subunion = _UnionMemberSubunion(cg_context.union, subunion)
-        func_decl, func_def = make_api_subunion_pred(subunion,
-                                                     subunion_members)
-        decls.append(func_decl)
-        defs.append(func_def)
-        defs.append(EmptyNode())
-        func_decl, func_def = make_api_subunion_get(subunion, subunion_members)
-        decls.append(func_decl)
-        defs.append(func_def)
-        defs.append(EmptyNode())
-        func_decl, func_def = make_api_subunion_set(subunion, subunion_members)
-        decls.append(func_decl)
-        defs.append(func_def)
-        defs.append(EmptyNode())
+        add(*make_api_subunion_pred(subunion, subunion_members))
+        add(*make_api_subunion_get(subunion, subunion_members))
+        add(*make_api_subunion_set(subunion, subunion_members))
         decls.append(EmptyNode())
 
     return decls, defs
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 5c78dd7..dccd9d97 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1341,6 +1341,7 @@
     "layout/layout_list_marker_test.cc",
     "layout/layout_media_test.cc",
     "layout/layout_multi_column_flow_thread_test.cc",
+    "layout/layout_object_factory_test.cc",
     "layout/layout_object_test.cc",
     "layout/layout_progress_test.cc",
     "layout/layout_replaced_test.cc",
diff --git a/third_party/blink/renderer/core/DIR_METADATA b/third_party/blink/renderer/core/DIR_METADATA
index fca4a1f..6d75bc54 100644
--- a/third_party/blink/renderer/core/DIR_METADATA
+++ b/third_party/blink/renderer/core/DIR_METADATA
@@ -1,5 +1,2 @@
-monorail {
-  component: "Blink"
-}
 
 team_email: "blink-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/app_history/app_history.cc b/third_party/blink/renderer/core/app_history/app_history.cc
index 7d81b1a..8d3aa88 100644
--- a/third_party/blink/renderer/core/app_history/app_history.cc
+++ b/third_party/blink/renderer/core/app_history/app_history.cc
@@ -5,9 +5,9 @@
 #include "third_party/blink/renderer/core/app_history/app_history.h"
 
 #include "third_party/blink/renderer/bindings/core/v8/script_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_app_history_navigate_event_init.h"
 #include "third_party/blink/renderer/core/app_history/app_history_entry.h"
 #include "third_party/blink/renderer/core/app_history/app_history_navigate_event.h"
-#include "third_party/blink/renderer/core/app_history/app_history_navigate_event_init.h"
 #include "third_party/blink/renderer/core/app_history/app_history_navigate_options.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/events/error_event.h"
diff --git a/third_party/blink/renderer/core/app_history/app_history_navigate_event.cc b/third_party/blink/renderer/core/app_history/app_history_navigate_event.cc
index 74d8f46..aca594e 100644
--- a/third_party/blink/renderer/core/app_history/app_history_navigate_event.cc
+++ b/third_party/blink/renderer/core/app_history/app_history_navigate_event.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/core/app_history/app_history_navigate_event.h"
 
-#include "third_party/blink/renderer/core/app_history/app_history_navigate_event_init.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_app_history_navigate_event_init.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/event_interface_names.h"
 #include "third_party/blink/renderer/core/event_type_names.h"
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 4e98dd5..a20093f 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -8185,6 +8185,12 @@
   if (DocumentLoader* loader = Loader())
     loader->NotifyPrerenderingDocumentActivated();
 
+  Vector<base::OnceClosure> callbacks;
+  callbacks.swap(will_dispatch_prerenderingchange_callbacks_);
+  for (auto& callback : callbacks) {
+    std::move(callback).Run();
+  }
+
   // https://jeremyroman.github.io/alternate-loading-modes/#prerendering-browsing-context-activate
   // Step 8.3.4 "Fire an event named prerenderingchange at doc."
   DispatchEvent(*Event::Create(event_type_names::kPrerenderingchange));
@@ -8197,6 +8203,12 @@
     frame->DidActivateForPrerendering();
 }
 
+void Document::AddWillDispatchPrerenderingchangeCallback(
+    base::OnceClosure closure) {
+  DCHECK(is_prerendering_);
+  will_dispatch_prerenderingchange_callbacks_.push_back(std::move(closure));
+}
+
 void Document::AddPostPrerenderingActivationStep(base::OnceClosure callback) {
   DCHECK(is_prerendering_);
   post_prerendering_activation_callbacks_.push_back(std::move(callback));
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 6eb556a..083cd83 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -1689,6 +1689,8 @@
 
   void ActivateForPrerendering();
 
+  void AddWillDispatchPrerenderingchangeCallback(base::OnceClosure);
+
   void AddPostPrerenderingActivationStep(base::OnceClosure callback);
 
   class CORE_EXPORT PaintPreviewScope {
@@ -1863,6 +1865,10 @@
   // https://github.com/jeremyroman/alternate-loading-modes/blob/main/prerendering-state.md#documentprerendering
   bool is_prerendering_;
 
+  // Callbacks to execute upon activation of a prerendered page, just before the
+  // prerenderingchange event is dispatched.
+  Vector<base::OnceClosure> will_dispatch_prerenderingchange_callbacks_;
+
   // The callback list for post-prerendering activation step.
   // https://jeremyroman.github.io/alternate-loading-modes/#document-post-prerendering-activation-steps-list
   Vector<base::OnceClosure> post_prerendering_activation_callbacks_;
diff --git a/third_party/blink/renderer/core/editing/commands/set_character_data_command_test.cc b/third_party/blink/renderer/core/editing/commands/set_character_data_command_test.cc
index b40ef7d..0a4f682 100644
--- a/third_party/blink/renderer/core/editing/commands/set_character_data_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/set_character_data_command_test.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/editing/commands/editing_state.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
 #include "third_party/blink/renderer/core/layout/layout_text_combine.h"
 
 namespace blink {
@@ -122,15 +123,26 @@
 }
 
 TEST_F(SetCharacterDataCommandTest, CombinedText) {
-  SetBodyContent(
-      "<div contenteditable style='writing-mode:vertical-lr; "
-      "-webkit-text-combine:horizontal' />");
+  InsertStyleElement(
+      "#sample {"
+      "text-combine-upright: all;"
+      "writing-mode:vertical-lr;"
+      "}");
+  SetBodyContent("<div contenteditable id=sample></div>");
 
+  const auto& sample_layout_object =
+      *To<LayoutBlockFlow>(GetElementById("sample")->GetLayoutObject());
   auto* text_node = To<Text>(GetDocument().body()->firstChild()->appendChild(
       GetDocument().CreateEditingTextNode("")));
   UpdateAllLifecyclePhasesForTest();
 
   ASSERT_TRUE(text_node->GetLayoutObject());
+  ASSERT_FALSE(sample_layout_object.IsLayoutNGObject());
+  EXPECT_EQ(R"DUMP(
+LayoutBlockFlow DIV id="sample" (editable)
+  +--LayoutTextCombine #text ""
+)DUMP",
+            ToSimpleLayoutTree(sample_layout_object));
   ASSERT_TRUE(text_node->GetLayoutObject()->IsCombineText());
   EXPECT_FALSE(
       To<LayoutTextCombine>(text_node->GetLayoutObject())->IsCombined());
@@ -141,6 +153,12 @@
   UpdateAllLifecyclePhasesForTest();
 
   ASSERT_TRUE(text_node->GetLayoutObject());
+  ASSERT_FALSE(sample_layout_object.IsLayoutNGObject());
+  EXPECT_EQ(R"DUMP(
+LayoutBlockFlow DIV id="sample" (editable)
+  +--LayoutTextCombine #text "text"
+)DUMP",
+            ToSimpleLayoutTree(sample_layout_object));
   ASSERT_TRUE(text_node->GetLayoutObject()->IsCombineText());
   EXPECT_TRUE(
       To<LayoutTextCombine>(text_node->GetLayoutObject())->IsCombined());
@@ -149,6 +167,12 @@
   UpdateAllLifecyclePhasesForTest();
 
   ASSERT_TRUE(text_node->GetLayoutObject());
+  ASSERT_FALSE(sample_layout_object.IsLayoutNGObject());
+  EXPECT_EQ(R"DUMP(
+LayoutBlockFlow DIV id="sample" (editable)
+  +--LayoutTextCombine #text ""
+)DUMP",
+            ToSimpleLayoutTree(sample_layout_object));
   ASSERT_TRUE(text_node->GetLayoutObject()->IsCombineText());
   EXPECT_FALSE(
       To<LayoutTextCombine>(text_node->GetLayoutObject())->IsCombined());
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 94b408a..10ffb30 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -13412,18 +13412,6 @@
             frame->GetDocument().CanonicalUrlForSharing());
 }
 
-TEST_F(WebFrameTest, NavigationTimingInfo) {
-  RegisterMockedHttpURLLoad("foo.html");
-  frame_test_helpers::WebViewHelper web_view_helper;
-  web_view_helper.InitializeAndLoad(base_url_ + "foo.html");
-  ResourceTimingInfo* navigation_timing_info = web_view_helper.LocalMainFrame()
-                                                   ->GetFrame()
-                                                   ->Loader()
-                                                   .GetDocumentLoader()
-                                                   ->GetNavigationTimingInfo();
-  EXPECT_EQ(navigation_timing_info->TransferSize(), static_cast<uint64_t>(34));
-}
-
 TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
   UseAndroidSettings();
   WebView().MainFrameViewWidget()->Resize(gfx::Size(490, 500));
diff --git a/third_party/blink/renderer/core/html/forms/DIR_METADATA b/third_party/blink/renderer/core/html/forms/DIR_METADATA
index a682370..48df82c 100644
--- a/third_party/blink/renderer/core/html/forms/DIR_METADATA
+++ b/third_party/blink/renderer/core/html/forms/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Forms"
 }
 
-team_email: "dom-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/html/html_br_element.cc b/third_party/blink/renderer/core/html/html_br_element.cc
index 8320f200..0741811 100644
--- a/third_party/blink/renderer/core/html/html_br_element.cc
+++ b/third_party/blink/renderer/core/html/html_br_element.cc
@@ -25,7 +25,8 @@
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css_value_keywords.h"
 #include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/layout/layout_br.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
 
 namespace blink {
 
@@ -63,7 +64,8 @@
 LayoutObject* HTMLBRElement::CreateLayoutObject(const ComputedStyle& style,
                                                 LegacyLayout legacy) {
   if (style.ContentBehavesAsNormal())
-    return new LayoutBR(this);
+    return LayoutObjectFactory::CreateBR(this, legacy);
+
   return LayoutObject::CreateObject(this, style, legacy);
 }
 
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index b0d688acb..079c7fb 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -34,6 +34,7 @@
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "media/base/logging_override_if_enabled.h"
 #include "media/base/media_content_type.h"
@@ -179,6 +180,35 @@
   kMaxValue = kInterruptedByLoad,
 };
 
+// The state of the HTMLMediaElement when ProgressEventTimerFired is invoked.
+// These values are histogrammed, so please only add values to the end.
+enum class ProgressEventTimerState {
+  // networkState is not NETWORK_LOADING.
+  kNotLoading,
+  // MediaShouldBeOpaque() is true.
+  kMediaShouldBeOpaque,
+  // "progress" event was scheduled.
+  kProgress,
+  // No progress. The "stalled" event was scheduled.
+  kStalled,
+  // No progress. No "stalled" event scheduled because a Media Source Attachment
+  // is used.
+  kHasMediaSourceAttachment,
+  // No progress. No "stalled" event scheduled because there was recent
+  // progress.
+  kRecentProgress,
+  // No progress. No "stalled" event scheduled because it was already scheduled.
+  kStalledEventAlreadyScheduled,
+  kMaxValue = kStalledEventAlreadyScheduled
+};
+
+// Records the state of the HTMLMediaElement when its "progress event" timer
+// fires.
+// TODO(crbug.com/1143317): Remove once the bug is fixed.
+void RecordProgressEventTimerState(ProgressEventTimerState state) {
+  UMA_HISTOGRAM_ENUMERATION("Media.ProgressEventTimerState", state);
+}
+
 static const base::TimeDelta kStalledNotificationInterval =
     base::TimeDelta::FromSeconds(3);
 
@@ -2060,15 +2090,20 @@
 }
 
 void HTMLMediaElement::ProgressEventTimerFired(TimerBase*) {
-  if (network_state_ != kNetworkLoading)
+  if (network_state_ != kNetworkLoading) {
+    RecordProgressEventTimerState(ProgressEventTimerState::kNotLoading);
     return;
+  }
 
   // If this is an cross-origin request, and we haven't discovered whether
   // the media is actually playable yet, don't fire any progress events as
   // those may let the page know information about the resource that it's
   // not supposed to know.
-  if (MediaShouldBeOpaque())
+  if (MediaShouldBeOpaque()) {
+    RecordProgressEventTimerState(
+        ProgressEventTimerState::kMediaShouldBeOpaque);
     return;
+  }
 
   DCHECK(previous_progress_time_);
 
@@ -2077,10 +2112,17 @@
     previous_progress_time_ = base::ElapsedTimer();
     sent_stalled_event_ = false;
     UpdateLayoutObject();
-  } else if (!media_source_attachment_ &&
-             previous_progress_time_->Elapsed() >
-                 kStalledNotificationInterval &&
-             !sent_stalled_event_) {
+    RecordProgressEventTimerState(ProgressEventTimerState::kProgress);
+  } else if (media_source_attachment_) {
+    RecordProgressEventTimerState(
+        ProgressEventTimerState::kHasMediaSourceAttachment);
+  } else if (previous_progress_time_->Elapsed() <=
+             kStalledNotificationInterval) {
+    RecordProgressEventTimerState(ProgressEventTimerState::kRecentProgress);
+  } else if (sent_stalled_event_) {
+    RecordProgressEventTimerState(
+        ProgressEventTimerState::kStalledEventAlreadyScheduled);
+  } else {
     // Note the !media_source_attachment_ condition above. The 'stalled' event
     // is not fired when using MSE. MSE's resource is considered 'local' (we
     // don't manage the download - the app does), so the HTML5 spec text around
@@ -2090,6 +2132,7 @@
     ScheduleEvent(event_type_names::kStalled);
     sent_stalled_event_ = true;
     SetShouldDelayLoadEvent(false);
+    RecordProgressEventTimerState(ProgressEventTimerState::kStalled);
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/build.gni b/third_party/blink/renderer/core/layout/build.gni
index 3dbe5db..207853d 100644
--- a/third_party/blink/renderer/core/layout/build.gni
+++ b/third_party/blink/renderer/core/layout/build.gni
@@ -333,6 +333,7 @@
   "ng/grid/ng_grid_track_collection.cc",
   "ng/grid/ng_grid_track_collection.h",
   "ng/inline/empty_offset_mapping_builder.h",
+  "ng/inline/layout_ng_br.h",
   "ng/inline/layout_ng_text.h",
   "ng/inline/layout_ng_text_fragment.h",
   "ng/inline/ng_abstract_inline_text_box.cc",
@@ -365,6 +366,8 @@
   "ng/inline/ng_inline_item_segment.h",
   "ng/inline/ng_inline_items_builder.cc",
   "ng/inline/ng_inline_items_builder.h",
+  "ng/inline/ng_inline_items_data.cc",
+  "ng/inline/ng_inline_items_data.h",
   "ng/inline/ng_inline_layout_algorithm.cc",
   "ng/inline/ng_inline_layout_algorithm.h",
   "ng/inline/ng_inline_node.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 19cdc2c..bdb96ea 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -2789,8 +2789,12 @@
     SetShouldCheckForPaintInvalidation();
   // In flipped blocks writing mode, our children can change physical location,
   // but their flipped location remains the same.
-  if (HasFlippedBlocksWritingMode())
-    SetSubtreeShouldCheckForPaintInvalidation();
+  if (HasFlippedBlocksWritingMode()) {
+    if (ChildrenInline())
+      SetSubtreeShouldDoFullPaintInvalidation();
+    else
+      SetSubtreeShouldCheckForPaintInvalidation();
+  }
 }
 
 bool LayoutBox::IntersectsVisibleViewport() const {
diff --git a/third_party/blink/renderer/core/layout/layout_br.h b/third_party/blink/renderer/core/layout/layout_br.h
index a77b93d..cd26d91 100644
--- a/third_party/blink/renderer/core/layout/layout_br.h
+++ b/third_party/blink/renderer/core/layout/layout_br.h
@@ -27,7 +27,7 @@
 // support for CSS2 :before and :after pseudo elements.
 namespace blink {
 
-class LayoutBR final : public LayoutText {
+class LayoutBR : public LayoutText {
  public:
   explicit LayoutBR(Node*);
   ~LayoutBR() override;
diff --git a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread_test.cc b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread_test.cc
index c9076142..ed1dc519 100644
--- a/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread_test.cc
+++ b/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread_test.cc
@@ -4,8 +4,6 @@
 
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 
-#include <sstream>
-
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/core/dom/text.h"
 #include "third_party/blink/renderer/core/html/html_div_element.h"
@@ -37,33 +35,6 @@
   String ColumnSetSignature(const char* multicol_id);
 
   void SetMulticolHTML(const String&);
-
-  // See also LayoutTreeAsText to dump with geometry and paint layers.
-  static std::string ToSimpleLayoutTree(const LayoutObject& layout_object) {
-    std::ostringstream ostream;
-    ostream << std::endl;
-    ToSimpleLayoutTree(ostream, layout_object, 0);
-    return ostream.str();
-  }
-
- private:
-  static void ToSimpleLayoutTree(std::ostream& ostream,
-                                 const LayoutObject& layout_object,
-                                 int depth) {
-    for (int i = 1; i < depth; ++i)
-      ostream << "|  ";
-    ostream << (depth ? "+--" : "") << layout_object.GetName() << " ";
-    if (auto* node = layout_object.GetNode())
-      ostream << *node;
-    else
-      ostream << "(anonymous)";
-    ostream << std::endl;
-    for (auto* child = layout_object.SlowFirstChild(); child;
-         child = child->NextSibling()) {
-      ostream << "  ";
-      ToSimpleLayoutTree(ostream, *child, depth + 1);
-    }
-  }
 };
 
 LayoutMultiColumnFlowThread* MultiColumnRenderingTest::FindFlowThread(
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc
index 2151fc07..f375c0de 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_br.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
@@ -75,7 +76,6 @@
 
 template <typename BaseType, typename NGType, typename LegacyType = BaseType>
 inline BaseType* CreateObject(Node& node,
-                              const ComputedStyle& style,
                               LegacyLayout legacy,
                               bool disable_ng_for_type = false) {
   Element* element = GetElementForLayoutObject(node);
@@ -110,11 +110,11 @@
   if (style.Display() == EDisplay::kListItem) {
     // Create a LayoutBlockFlow with a list marker
     return CreateObject<LayoutBlockFlow, LayoutNGListItem, LayoutListItem>(
-        node, style, legacy);
+        node, legacy);
   }
 
   // Create a plain LayoutBlockFlow
-  return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow>(node, style, legacy);
+  return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow>(node, legacy);
 }
 
 // static
@@ -123,14 +123,14 @@
     const ComputedStyle& style,
     LegacyLayout legacy) {
   return CreateObject<LayoutBlock, LayoutNGBlockFlow,
-                      LayoutDeprecatedFlexibleBox>(node, style, legacy);
+                      LayoutDeprecatedFlexibleBox>(node, legacy);
 }
 
 LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node,
                                                     const ComputedStyle& style,
                                                     LegacyLayout legacy) {
   return CreateObject<LayoutBlock, LayoutNGFlexibleBox, LayoutFlexibleBox>(
-      node, style, legacy);
+      node, legacy);
 }
 
 LayoutBlock* LayoutObjectFactory::CreateGrid(Node& node,
@@ -140,7 +140,7 @@
   if (disable_ng_for_type)
     UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByGrid);
   return CreateObject<LayoutBlock, LayoutNGGrid, LayoutGrid>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutBlock* LayoutObjectFactory::CreateMath(Node& node,
@@ -151,11 +151,10 @@
   bool disable_ng_for_type = !RuntimeEnabledFeatures::MathMLCoreEnabled();
   if (To<MathMLElement>(node).IsTokenElement()) {
     return CreateObject<LayoutBlockFlow, LayoutNGMathMLBlockFlow,
-                        LayoutBlockFlow>(node, style, legacy,
-                                         disable_ng_for_type);
+                        LayoutBlockFlow>(node, legacy, disable_ng_for_type);
   }
   return CreateObject<LayoutBlock, LayoutNGMathMLBlock, LayoutBlockFlow>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutObject* LayoutObjectFactory::CreateListMarker(Node& node,
@@ -169,17 +168,17 @@
   if (style.ContentBehavesAsNormal()) {
     if (is_inside) {
       return CreateObject<LayoutObject, LayoutNGInsideListMarker,
-                          LayoutListMarker>(node, style, legacy);
+                          LayoutListMarker>(node, legacy);
     }
     return CreateObject<LayoutObject, LayoutNGOutsideListMarker,
-                        LayoutListMarker>(node, style, legacy);
+                        LayoutListMarker>(node, legacy);
   }
   if (is_inside) {
     return CreateObject<LayoutObject, LayoutNGInsideListMarker,
-                        LayoutInsideListMarker>(node, style, legacy);
+                        LayoutInsideListMarker>(node, legacy);
   }
   return CreateObject<LayoutObject, LayoutNGOutsideListMarker,
-                      LayoutOutsideListMarker>(node, style, legacy);
+                      LayoutOutsideListMarker>(node, legacy);
 }
 
 LayoutBlock* LayoutObjectFactory::CreateTable(Node& node,
@@ -189,15 +188,14 @@
   if (disable_ng_for_type)
     UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
   return CreateObject<LayoutBlock, LayoutNGTable, LayoutTable>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutTableCaption* LayoutObjectFactory::CreateTableCaption(
     Node& node,
     const ComputedStyle& style,
     LegacyLayout legacy) {
-  return CreateObject<LayoutTableCaption, LayoutNGTableCaption>(node, style,
-                                                                legacy);
+  return CreateObject<LayoutTableCaption, LayoutNGTableCaption>(node, legacy);
 }
 
 LayoutBlockFlow* LayoutObjectFactory::CreateTableCell(
@@ -206,10 +204,10 @@
     LegacyLayout legacy) {
   if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
     return CreateObject<LayoutBlockFlow, LayoutNGTableCell, LayoutTableCell>(
-        node, style, legacy);
+        node, legacy);
   } else {
     return CreateObject<LayoutBlockFlow, LayoutNGTableCellLegacy,
-                        LayoutTableCell>(node, style, legacy);
+                        LayoutTableCell>(node, legacy);
   }
 }
 
@@ -220,7 +218,7 @@
   if (disable_ng_for_type)
     UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
   return CreateObject<LayoutBox, LayoutNGTableColumn, LayoutTableCol>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutBox* LayoutObjectFactory::CreateTableRow(Node& node,
@@ -230,7 +228,7 @@
   if (disable_ng_for_type)
     UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
   return CreateObject<LayoutBox, LayoutNGTableRow, LayoutTableRow>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutBox* LayoutObjectFactory::CreateTableSection(Node& node,
@@ -240,21 +238,20 @@
   if (disable_ng_for_type)
     UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
   return CreateObject<LayoutBox, LayoutNGTableSection, LayoutTableSection>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
 }
 
 LayoutObject* LayoutObjectFactory::CreateButton(Node& node,
                                                 const ComputedStyle& style,
                                                 LegacyLayout legacy) {
-  return CreateObject<LayoutBlock, LayoutNGButton, LayoutButton>(node, style,
-                                                                 legacy);
+  return CreateObject<LayoutBlock, LayoutNGButton, LayoutButton>(node, legacy);
 }
 
 LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node,
                                                  const ComputedStyle& style,
                                                  LegacyLayout legacy) {
-  return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(
-      node, style, legacy);
+  return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(node,
+                                                                     legacy);
 }
 
 LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl(
@@ -262,14 +259,14 @@
     const ComputedStyle& style,
     LegacyLayout legacy) {
   return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow,
-                      LayoutFileUploadControl>(node, style, legacy);
+                      LayoutFileUploadControl>(node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateSliderTrack(Node& node,
                                                      const ComputedStyle& style,
                                                      LegacyLayout legacy) {
   return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutSliderTrack>(
-      node, style, legacy);
+      node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateTextControlInnerEditor(
@@ -277,7 +274,7 @@
     const ComputedStyle& style,
     LegacyLayout legacy) {
   return CreateObject<LayoutBlockFlow, LayoutNGTextControlInnerEditor,
-                      LayoutTextControlInnerEditor>(node, style, legacy);
+                      LayoutTextControlInnerEditor>(node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateTextControlMultiLine(
@@ -285,7 +282,7 @@
     const ComputedStyle& style,
     LegacyLayout legacy) {
   return CreateObject<LayoutBlockFlow, LayoutNGTextControlMultiLine,
-                      LayoutTextControlMultiLine>(node, style, legacy);
+                      LayoutTextControlMultiLine>(node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateTextControlSingleLine(
@@ -293,7 +290,7 @@
     const ComputedStyle& style,
     LegacyLayout legacy) {
   return CreateObject<LayoutBlockFlow, LayoutNGTextControlSingleLine,
-                      LayoutTextControlSingleLine>(node, style, legacy);
+                      LayoutTextControlSingleLine>(node, legacy);
 }
 
 LayoutText* LayoutObjectFactory::CreateText(Node* node,
@@ -333,21 +330,20 @@
 LayoutProgress* LayoutObjectFactory::CreateProgress(Node* node,
                                                     const ComputedStyle& style,
                                                     LegacyLayout legacy) {
-  return CreateObject<LayoutProgress, LayoutNGProgress>(*node, style, legacy);
+  return CreateObject<LayoutProgress, LayoutNGProgress>(*node, legacy);
 }
 
 LayoutRubyAsBlock* LayoutObjectFactory::CreateRubyAsBlock(
     Node* node,
     const ComputedStyle& style,
     LegacyLayout legacy) {
-  return CreateObject<LayoutRubyAsBlock, LayoutNGRubyAsBlock>(*node, style,
-                                                              legacy);
+  return CreateObject<LayoutRubyAsBlock, LayoutNGRubyAsBlock>(*node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateRubyText(Node* node,
                                                   const ComputedStyle& style,
                                                   LegacyLayout legacy) {
-  return CreateObject<LayoutRubyText, LayoutNGRubyText>(*node, style, legacy);
+  return CreateObject<LayoutRubyText, LayoutNGRubyText>(*node, legacy);
 }
 
 LayoutObject* LayoutObjectFactory::CreateSVGText(Node& node,
@@ -355,7 +351,11 @@
                                                  LegacyLayout legacy) {
   const bool disable_ng_for_type = !RuntimeEnabledFeatures::SVGTextNGEnabled();
   return CreateObject<LayoutBlockFlow, LayoutNGSVGText, LayoutSVGText>(
-      node, style, legacy, disable_ng_for_type);
+      node, legacy, disable_ng_for_type);
+}
+
+LayoutObject* LayoutObjectFactory::CreateBR(Node* node, LegacyLayout legacy) {
+  return CreateObject<LayoutObject, LayoutNGBR, LayoutBR>(*node, legacy);
 }
 
 LayoutBox* LayoutObjectFactory::CreateAnonymousTableWithParent(
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h
index 9a174a6..4cb7024 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -106,7 +106,9 @@
                                      const ComputedStyle& style,
                                      LegacyLayout legacy);
 
-  // Anonoymous creation methods
+  static LayoutObject* CreateBR(Node*, LegacyLayout);
+
+  // Anonymous creation methods
 
   // |child_forces_legacy| true if creating parents boxes for legacy child.
   // Table must match child's type.
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory_test.cc b/third_party/blink/renderer/core/layout/layout_object_factory_test.cc
new file mode 100644
index 0000000..d1eedc52
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/layout_object_factory_test.cc
@@ -0,0 +1,38 @@
+// 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/layout_object_factory.h"
+
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+
+class LayoutObjectFactoryTest : public ::testing::WithParamInterface<bool>,
+                                private ScopedLayoutNGForTest,
+                                public RenderingTest {
+ protected:
+  LayoutObjectFactoryTest() : ScopedLayoutNGForTest(GetParam()) {}
+
+  bool LayoutNGEnabled() const {
+    return RuntimeEnabledFeatures::LayoutNGEnabled();
+  }
+};
+
+INSTANTIATE_TEST_SUITE_P(LayoutObjectFactoryTest,
+                         LayoutObjectFactoryTest,
+                         ::testing::Bool());
+
+TEST_P(LayoutObjectFactoryTest, BR) {
+  SetBodyInnerHTML("<br id=sample>");
+  const auto& layout_object = *GetLayoutObjectByElementId("sample");
+
+  if (LayoutNGEnabled())
+    EXPECT_TRUE(layout_object.IsLayoutNGObject());
+  else
+    EXPECT_FALSE(layout_object.IsLayoutNGObject());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/DIR_METADATA b/third_party/blink/renderer/core/layout/ng/DIR_METADATA
deleted file mode 100644
index 3611c38f..0000000
--- a/third_party/blink/renderer/core/layout/ng/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>Layout"
-}
-
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA b/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA
deleted file mode 100644
index 3611c38f..0000000
--- a/third_party/blink/renderer/core/layout/ng/custom/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>Layout"
-}
-
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/layout/ng/inline/layout_ng_br.h b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_br.h
new file mode 100644
index 0000000..de9733e47
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/layout_ng_br.h
@@ -0,0 +1,41 @@
+// 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_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_BR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_BR_H_
+
+#include "third_party/blink/renderer/core/layout/layout_br.h"
+
+namespace blink {
+
+// This class is identical to |LayoutBR| except for this class returns true
+// for |IsLayoutNGObject()| and |NGInlineItem| support, to become child of
+// |LayoutNGTextCombine|. See also |LayoutNGWordBreak|.
+// TODO(yosin): Once we get rid of |IsLayoutNGObject()|, we should unify this
+// class |LayoutBR|.
+class CORE_EXPORT LayoutNGBR final : public LayoutBR {
+ public:
+  explicit LayoutNGBR(Node* node) : LayoutBR(node) {}
+
+  bool IsLayoutNGObject() const final {
+    NOT_DESTROYED();
+    return true;
+  }
+
+ private:
+  const base::span<NGInlineItem>* GetNGInlineItems() const final {
+    NOT_DESTROYED();
+    return &inline_items_;
+  }
+  base::span<NGInlineItem>* GetNGInlineItems() final {
+    NOT_DESTROYED();
+    return &inline_items_;
+  }
+
+  base::span<NGInlineItem> inline_items_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_BR_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
index 262e2ff..0cb6ef7 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
@@ -191,17 +191,6 @@
   return index + 1;
 }
 
-void NGInlineItemsData::GetOpenTagItems(wtf_size_t size,
-                                        OpenTagItems* open_items) const {
-  DCHECK_LE(size, items.size());
-  for (const NGInlineItem& item : base::make_span(items.data(), size)) {
-    if (item.Type() == NGInlineItem::kOpenTag)
-      open_items->push_back(&item);
-    else if (item.Type() == NGInlineItem::kCloseTag)
-      open_items->pop_back();
-  }
-}
-
 const Font& NGInlineItem::FontWithSVGScaling() const {
   if (const auto* svg_text = DynamicTo<LayoutSVGInlineText>(layout_object_)) {
     DCHECK(RuntimeEnabledFeatures::SVGTextNGEnabled());
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
index 45840f3..d520533 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -5,20 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_H_
 
+#include <unicode/ubidi.h>
+
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_segment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_text_type.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/fonts/shaping/run_segmenter.h"
-#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 
-#include <unicode/ubidi.h>
-#include <unicode/uscript.h>
-
 namespace blink {
 
 class LayoutObject;
@@ -280,42 +276,6 @@
   DCHECK_LE(offset, end_offset_);
 }
 
-// Represents a text content with a list of NGInlineItem. A node may have an
-// additional NGInlineItemsData for ::first-line pseudo element.
-struct CORE_EXPORT NGInlineItemsData {
-  USING_FAST_MALLOC(NGInlineItemsData);
-
- public:
-  // Text content for all inline items represented by a single NGInlineNode.
-  // Encoded either as UTF-16 or latin-1 depending on the content.
-  String text_content;
-  Vector<NGInlineItem> items;
-
-  // Cache RunSegmenter segments when at least one item has multiple runs.
-  // Set to nullptr when all items has only single run, which is common case for
-  // most writing systems. However, in multi-script writing systems such as
-  // Japanese, almost every item has multiple runs.
-  std::unique_ptr<NGInlineItemSegments> segments;
-
-  // The DOM to text content offset mapping of this inline node.
-  std::unique_ptr<NGOffsetMapping> offset_mapping;
-
-  bool IsValidOffset(unsigned index, unsigned offset) const {
-    return index < items.size() && items[index].IsValidOffset(offset);
-  }
-
-  void AssertOffset(unsigned index, unsigned offset) const {
-    items[index].AssertOffset(offset);
-  }
-  void AssertEndOffset(unsigned index, unsigned offset) const {
-    items[index].AssertEndOffset(offset);
-  }
-
-  // Get a list of |kOpenTag| that are open at |size|.
-  using OpenTagItems = Vector<const NGInlineItem*, 16>;
-  void GetOpenTagItems(wtf_size_t size, OpenTagItems* open_items) const;
-};
-
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEM_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.cc
new file mode 100644
index 0000000..60e0148
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.cc
@@ -0,0 +1,20 @@
+// 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.
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h"
+
+namespace blink {
+
+void NGInlineItemsData::GetOpenTagItems(wtf_size_t size,
+                                        OpenTagItems* open_items) const {
+  DCHECK_LE(size, items.size());
+  for (const NGInlineItem& item : base::make_span(items.data(), size)) {
+    if (item.Type() == NGInlineItem::kOpenTag)
+      open_items->push_back(&item);
+    else if (item.Type() == NGInlineItem::kCloseTag)
+      open_items->pop_back();
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h
new file mode 100644
index 0000000..594561bb
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_DATA_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_DATA_H_
+
+#include <memory>
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class NGInlineItemSegments;
+class NGOffsetMapping;
+
+// Represents a text content with a list of NGInlineItem. A node may have an
+// additional NGInlineItemsData for ::first-line pseudo element.
+struct CORE_EXPORT NGInlineItemsData {
+  USING_FAST_MALLOC(NGInlineItemsData);
+
+ public:
+  // Text content for all inline items represented by a single NGInlineNode.
+  // Encoded either as UTF-16 or latin-1 depending on the content.
+  String text_content;
+  Vector<NGInlineItem> items;
+
+  // Cache RunSegmenter segments when at least one item has multiple runs.
+  // Set to nullptr when all items has only single run, which is common case for
+  // most writing systems. However, in multi-script writing systems such as
+  // Japanese, almost every item has multiple runs.
+  std::unique_ptr<NGInlineItemSegments> segments;
+
+  // The DOM to text content offset mapping of this inline node.
+  std::unique_ptr<NGOffsetMapping> offset_mapping;
+
+  bool IsValidOffset(unsigned index, unsigned offset) const {
+    return index < items.size() && items[index].IsValidOffset(offset);
+  }
+
+  void AssertOffset(unsigned index, unsigned offset) const {
+    items[index].AssertOffset(offset);
+  }
+  void AssertEndOffset(unsigned index, unsigned offset) const {
+    items[index].AssertEndOffset(offset);
+  }
+
+  // Get a list of |kOpenTag| that are open at |size|.
+  using OpenTagItems = Vector<const NGInlineItem*, 16>;
+  void GetOpenTagItems(wtf_size_t size, OpenTagItems* open_items) const;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_ITEMS_DATA_H_
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index 06129bc..dc58dc3d 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_NODE_DATA_H_
 
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_data.h"
 #include "third_party/blink/renderer/core/layout/ng/svg/svg_inline_node_data.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 041872f..6a71654d3 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -73,6 +73,7 @@
       needs_positioning_values_update_(false),
       needs_text_metrics_update_(false) {
   DCHECK(IsA<SVGTextElement>(node));
+  UseCounter::Count(GetDocument(), WebFeature::kSVGText);
 }
 
 LayoutSVGText::~LayoutSVGText() {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
index 9219680..fd49e85a 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h"
 
 #include "base/auto_reset.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
 #include "third_party/blink/renderer/core/layout/api/line_layout_svg_text_path.h"
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
@@ -32,6 +33,7 @@
 #include "third_party/blink/renderer/core/svg/svg_element.h"
 #include "third_party/blink/renderer/core/svg/svg_length_context.h"
 #include "third_party/blink/renderer/core/svg/svg_text_content_element.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 
 namespace blink {
 
@@ -44,6 +46,7 @@
       is_vertical_text_(false),
       in_path_layout_(false),
       text_length_spacing_in_effect_(false),
+      last_text_box_was_in_text_path_(false),
       text_path_(nullptr),
       text_path_current_offset_(0),
       text_path_displacement_(0),
@@ -77,6 +80,10 @@
       if (has_x)
         text_path_current_offset_ = data.x + text_path_start_offset_;
     }
+  } else if ((!has_x || !has_y) && last_text_box_was_in_text_path_) {
+    UseCounter::Count(descendant_text_nodes_[0]->GetDocument(),
+                      WebFeature::kSVGTextHangingFromPath);
+    last_text_box_was_in_text_path_ = false;
   }
   return has_x || has_y;
 }
@@ -262,12 +269,14 @@
       text_length_spacing_in_effect_ || DefinesTextLengthWithSpacing(start);
   base::AutoReset<bool> text_length_spacing_scope(
       &text_length_spacing_in_effect_, text_length_spacing_in_effect);
+  last_text_box_was_in_text_path_ = false;
 
   for (InlineBox* child = start->FirstChild(); child;
        child = child->NextOnLine()) {
     if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(child)) {
       DCHECK(child->GetLineLayoutItem().IsSVGInlineText());
       LayoutInlineTextBox(svg_inline_text_box);
+      last_text_box_was_in_text_path_ = false;
     } else {
       // Skip generated content.
       Node* node = child->GetLineLayoutItem().GetNode();
@@ -283,6 +292,7 @@
 
       if (is_text_path)
         EndTextPathLayout();
+      last_text_box_was_in_text_path_ = is_text_path;
     }
   }
 }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h
index 0a84048..00a19a3 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h
@@ -91,6 +91,7 @@
   bool is_vertical_text_;
   bool in_path_layout_;
   bool text_length_spacing_in_effect_;
+  bool last_text_box_was_in_text_path_;
 
   // Text on path layout
   std::unique_ptr<PathPositionMapper> text_path_;
diff --git a/third_party/blink/renderer/core/loader/cross_thread_resource_timing_info_copier.cc b/third_party/blink/renderer/core/loader/cross_thread_resource_timing_info_copier.cc
index e4797bf2..904f00a 100644
--- a/third_party/blink/renderer/core/loader/cross_thread_resource_timing_info_copier.cc
+++ b/third_party/blink/renderer/core/loader/cross_thread_resource_timing_info_copier.cc
@@ -32,7 +32,7 @@
       info->connection_info.IsolatedCopy(),
       info->timing ? info->timing->Clone() : nullptr,
       info->last_redirect_end_time, info->response_end, info->context_type,
-      info->request_destination, info->transfer_size, info->encoded_body_size,
+      info->request_destination, info->cache_state, info->encoded_body_size,
       info->decoded_body_size, info->did_reuse_connection,
       info->is_secure_transport, info->allow_timing_details,
       info->allow_redirect_details, info->allow_negative_values,
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 25a6b66..0ef60d9 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -936,8 +936,6 @@
       // sizes.
       // TODO(yoav): copy the sizes info directly.
       navigation_timing_info_->SetFinalResponse(response_);
-      navigation_timing_info_->AddFinalTransferSize(
-          total_encoded_data_length == -1 ? 0 : total_encoded_data_length);
       if (report_timing_info_to_parent_) {
         navigation_timing_info_->SetLoadResponseEnd(completion_time);
         if (state_ >= kCommitted) {
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.cc b/third_party/blink/renderer/core/paint/background_image_geometry.cc
index 74a0075..23ea702 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.cc
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.cc
@@ -38,10 +38,11 @@
   return space;
 }
 
-float ComputeTilePhase(LayoutUnit position, LayoutUnit tile_extent) {
+LayoutUnit ComputeTilePhase(LayoutUnit position, LayoutUnit tile_extent) {
   // Assuming a non-integral number of tiles, find out how much of the
   // partial tile is visible. That is the phase.
-  return tile_extent ? tile_extent - IntMod(position, tile_extent) : 0.0f;
+  return tile_extent ? tile_extent - IntMod(position, tile_extent)
+                     : LayoutUnit();
 }
 
 bool FixedBackgroundPaintsInLocalCoordinates(
@@ -90,7 +91,7 @@
                                            LayoutUnit x_offset,
                                            LayoutUnit snapped_x_offset) {
   if (NeedsFullSizeDestination(fill_layer)) {
-    SetPhaseX(-x_offset.ToFloat());
+    SetPhaseX(-x_offset);
     SetSpaceSize(
         PhysicalSize(unsnapped_dest_rect_.Width(), SpaceSize().height));
     return;
@@ -109,11 +110,11 @@
     unsnapped_dest_rect_.SetWidth(tile_size_.width);
     snapped_dest_rect_.SetWidth(tile_size_.width);
 
-    SetPhaseX(0);
+    SetPhaseX(LayoutUnit());
   } else {
     // Otherwise, if the offset is negative use it to move the image under
     // the dest rect (since we can't paint outside the paint_rect).
-    SetPhaseX(-x_offset.ToFloat());
+    SetPhaseX(-x_offset);
 
     // Reduce the width of the dest rect to draw only the portion of the
     // tile that remains visible after offsetting the image.
@@ -131,7 +132,7 @@
                                            LayoutUnit y_offset,
                                            LayoutUnit snapped_y_offset) {
   if (NeedsFullSizeDestination(fill_layer)) {
-    SetPhaseY(-y_offset.ToFloat());
+    SetPhaseY(-y_offset);
     SetSpaceSize(
         PhysicalSize(SpaceSize().width, unsnapped_dest_rect_.Height()));
     return;
@@ -150,11 +151,11 @@
     unsnapped_dest_rect_.SetHeight(tile_size_.height);
     snapped_dest_rect_.SetHeight(tile_size_.height);
 
-    SetPhaseY(0);
+    SetPhaseY(LayoutUnit());
   } else {
     // Otherwise, if the offset is negative, use it to move the image under
     // the dest rect (since we can't paint outside the paint_rect).
-    SetPhaseY(-y_offset.ToFloat());
+    SetPhaseY(-y_offset);
 
     // Reduce the height of the dest rect to draw only the portion of the
     // tile that remains visible after offsetting the image.
@@ -187,7 +188,7 @@
     SetPhaseX(
         ComputeTilePhase(computed_position + extra_offset, tile_size_.width));
   } else {
-    SetPhaseX(0);
+    SetPhaseX(LayoutUnit());
   }
   SetSpaceSize(PhysicalSize(LayoutUnit(), SpaceSize().height));
 }
@@ -211,7 +212,7 @@
     SetPhaseY(
         ComputeTilePhase(computed_position + extra_offset, tile_size_.height));
   } else {
-    SetPhaseY(0);
+    SetPhaseY(LayoutUnit());
   }
   SetSpaceSize(PhysicalSize(SpaceSize().width, LayoutUnit()));
 }
@@ -232,10 +233,10 @@
 
 void BackgroundImageGeometry::UseFixedAttachment(
     const PhysicalOffset& attachment_point) {
-  PhysicalOffset aligned_point = attachment_point;
-  phase_.Move(
-      std::max((aligned_point.left - unsnapped_dest_rect_.X()).ToFloat(), 0.f),
-      std::max((aligned_point.top - unsnapped_dest_rect_.Y()).ToFloat(), 0.f));
+  PhysicalOffset fixed_adjustment =
+      attachment_point - unsnapped_dest_rect_.offset;
+  fixed_adjustment.ClampNegativeToZero();
+  phase_ += fixed_adjustment;
 }
 
 enum ColumnGroupDirection { kColumnGroupStart, kColumnGroupEnd };
diff --git a/third_party/blink/renderer/core/paint/background_image_geometry.h b/third_party/blink/renderer/core/paint/background_image_geometry.h
index dc6c463..3ef3b8f 100644
--- a/third_party/blink/renderer/core/paint/background_image_geometry.h
+++ b/third_party/blink/renderer/core/paint/background_image_geometry.h
@@ -75,7 +75,7 @@
   // Phase() represents the point in the image that will appear at (0,0) in the
   // destination space. The point is defined in TileSize() coordinates, that is,
   // in the scaled image.
-  const FloatPoint& Phase() const { return phase_; }
+  const PhysicalOffset& Phase() const { return phase_; }
 
   // SpaceSize() represents extra width and height that may be added to
   // the image if used as a pattern with background-repeat: space.
@@ -102,8 +102,8 @@
   void SetSpaceSize(const PhysicalSize& repeat_spacing) {
     repeat_spacing_ = repeat_spacing;
   }
-  void SetPhaseX(float x) { phase_.SetX(x); }
-  void SetPhaseY(float y) { phase_.SetY(y); }
+  void SetPhaseX(LayoutUnit x) { phase_.left = x; }
+  void SetPhaseY(LayoutUnit y) { phase_.top = y; }
 
   void SetNoRepeatX(const FillLayer&,
                     LayoutUnit x_offset,
@@ -183,7 +183,7 @@
 
   PhysicalRect unsnapped_dest_rect_;
   PhysicalRect snapped_dest_rect_;
-  FloatPoint phase_;
+  PhysicalOffset phase_;
   PhysicalSize tile_size_;
   PhysicalSize repeat_spacing_;
   bool has_non_local_geometry_ = false;
diff --git a/third_party/blink/renderer/core/paint/box_painter_base.cc b/third_party/blink/renderer/core/paint/box_painter_base.cc
index 963c314a..9acb533 100644
--- a/third_party/blink/renderer/core/paint/box_painter_base.cc
+++ b/third_party/blink/renderer/core/paint/box_painter_base.cc
@@ -668,7 +668,7 @@
       // border-snapped destination rect.
       image_tile = ComputePhaseForBackground(
           FloatPoint(geometry.SnappedDestRect().offset),
-          FloatSize(geometry.TileSize()), geometry.Phase(),
+          FloatSize(geometry.TileSize()), FloatPoint(geometry.Phase()),
           FloatSize(geometry.SpaceSize()));
 
       // Force the image tile to LayoutUnit precision, which is the precision
@@ -899,7 +899,7 @@
         FloatRect(image->Rect()), FloatRect(scrolled_paint_rect));
     DrawTiledBackground(
         context, image, FloatSize(geometry.UnsnappedDestRect().size),
-        FloatRect(geometry.SnappedDestRect()), geometry.Phase(),
+        FloatRect(geometry.SnappedDestRect()), FloatPoint(geometry.Phase()),
         FloatSize(geometry.TileSize()), composite_op,
         FloatSize(geometry.SpaceSize()),
         node && node->ComputedStyleRef().HasFilterInducingProperty(),
diff --git a/third_party/blink/renderer/core/paint/compositing/DIR_METADATA b/third_party/blink/renderer/core/paint/compositing/DIR_METADATA
index 096eaac..378163f 100644
--- a/third_party/blink/renderer/core/paint/compositing/DIR_METADATA
+++ b/third_party/blink/renderer/core/paint/compositing/DIR_METADATA
@@ -2,4 +2,3 @@
   component: "Blink>Compositing"
 }
 
-team_email: "paint-dev@chromium.org"
diff --git a/third_party/blink/renderer/core/svg/svg_graphics_element.cc b/third_party/blink/renderer/core/svg/svg_graphics_element.cc
index 314fa30..aba5ccc 100644
--- a/third_party/blink/renderer/core/svg/svg_graphics_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_graphics_element.cc
@@ -22,6 +22,7 @@
 #include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
 
 #include "third_party/blink/renderer/core/css/style_change_reason.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/svg/svg_animated_transform_list.h"
 #include "third_party/blink/renderer/core/svg/svg_element_rare_data.h"
@@ -29,6 +30,7 @@
 #include "third_party/blink/renderer/core/svg/svg_rect_tear_off.h"
 #include "third_party/blink/renderer/core/svg_names.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
 #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
 
 namespace blink {
@@ -185,8 +187,12 @@
 
   // FIXME: Eventually we should support getBBox for detached elements.
   FloatRect boundingBox;
-  if (GetLayoutObject())
+  if (const auto* layout_object = GetLayoutObject()) {
     boundingBox = GetBBox();
+
+    if (layout_object->IsSVGText() || layout_object->IsSVGInline())
+      UseCounter::Count(GetDocument(), WebFeature::kGetBBoxForText);
+  }
   return SVGRectTearOff::CreateDetached(boundingBox);
 }
 
diff --git a/third_party/blink/renderer/core/testing/page_test_base.cc b/third_party/blink/renderer/core/testing/page_test_base.cc
index 58db5bd..6565285 100644
--- a/third_party/blink/renderer/core/testing/page_test_base.cc
+++ b/third_party/blink/renderer/core/testing/page_test_base.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
 
+#include <sstream>
+
 #include "base/callback.h"
 #include "base/test/bind.h"
 #include "base/time/default_tick_clock.h"
@@ -19,6 +21,7 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/html_collection.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/testing/mock_policy_container_host.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
@@ -38,6 +41,24 @@
       tag_name, CreateElementFlags::ByCreateElement());
 }
 
+void ToSimpleLayoutTree(std::ostream& ostream,
+                        const LayoutObject& layout_object,
+                        int depth) {
+  for (int i = 1; i < depth; ++i)
+    ostream << "|  ";
+  ostream << (depth ? "+--" : "") << layout_object.GetName() << " ";
+  if (auto* node = layout_object.GetNode())
+    ostream << *node;
+  else
+    ostream << "(anonymous)";
+  ostream << std::endl;
+  for (auto* child = layout_object.SlowFirstChild(); child;
+       child = child->NextSibling()) {
+    ostream << "  ";
+    ToSimpleLayoutTree(ostream, *child, depth + 1);
+  }
+}
+
 }  // namespace
 
 PageTestBase::MockClipboardHostProvider::MockClipboardHostProvider(
@@ -274,4 +295,14 @@
                    : base::DefaultTickClock::GetInstance();
 }
 
+// See also LayoutTreeAsText to dump with geometry and paint layers.
+// static
+std::string PageTestBase::ToSimpleLayoutTree(
+    const LayoutObject& layout_object) {
+  std::ostringstream ostream;
+  ostream << std::endl;
+  ::blink::ToSimpleLayoutTree(ostream, layout_object, 0);
+  return ostream.str();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/page_test_base.h b/third_party/blink/renderer/core/testing/page_test_base.h
index f56eb70..d0170e0 100644
--- a/third_party/blink/renderer/core/testing/page_test_base.h
+++ b/third_party/blink/renderer/core/testing/page_test_base.h
@@ -99,6 +99,8 @@
   // See external/wpt/css/fonts/ahem/README for more about the 'Ahem' font.
   static void LoadAhem(LocalFrame&);
 
+  static std::string ToSimpleLayoutTree(const LayoutObject& layout_object);
+
  protected:
   void LoadAhem();
   void EnablePlatform();
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc
index 29911109..cc63f8a3 100644
--- a/third_party/blink/renderer/core/timing/performance.cc
+++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -590,7 +590,7 @@
     result->last_redirect_end_time = base::TimeTicks();
   }
 
-  result->transfer_size = info.TransferSize();
+  result->cache_state = info.CacheState();
   result->encoded_body_size = final_response.EncodedBodyLength();
   result->decoded_body_size = final_response.DecodedBodyLength();
   result->did_reuse_connection = final_response.ConnectionReused();
diff --git a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
index 322cd00..fa42819 100644
--- a/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_navigation_timing.cc
@@ -112,7 +112,8 @@
 }
 
 uint64_t PerformanceNavigationTiming::GetTransferSize() const {
-  return resource_timing_info_->TransferSize();
+  return PerformanceResourceTiming::GetTransferSize(
+      resource_timing_info_->FinalResponse().EncodedBodyLength(), CacheState());
 }
 
 uint64_t PerformanceNavigationTiming::GetEncodedBodySize() const {
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.cc b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
index eb3d907..2d10e649 100644
--- a/third_party/blink/renderer/core/timing/performance_resource_timing.cc
+++ b/third_party/blink/renderer/core/timing/performance_resource_timing.cc
@@ -80,7 +80,7 @@
       response_end_(info.response_end),
       context_type_(info.context_type),
       request_destination_(info.request_destination),
-      transfer_size_(info.transfer_size),
+      cache_state_(info.cache_state),
       encoded_body_size_(info.encoded_body_size),
       decoded_body_size_(info.decoded_body_size),
       did_reuse_connection_(info.did_reuse_connection),
@@ -143,8 +143,23 @@
   return did_reuse_connection_;
 }
 
+uint64_t PerformanceResourceTiming::GetTransferSize(
+    uint64_t encoded_body_size,
+    mojom::blink::CacheState cache_state) {
+  switch (cache_state) {
+    case mojom::blink::CacheState::kLocal:
+      return 0;
+    case mojom::blink::CacheState::kValidated:
+      return kHeaderSize;
+    case mojom::blink::CacheState::kNone:
+      return encoded_body_size + kHeaderSize;
+  }
+  NOTREACHED();
+  return 0;
+}
+
 uint64_t PerformanceResourceTiming::GetTransferSize() const {
-  return transfer_size_;
+  return GetTransferSize(encoded_body_size_, cache_state_);
 }
 
 uint64_t PerformanceResourceTiming::GetEncodedBodySize() const {
diff --git a/third_party/blink/renderer/core/timing/performance_resource_timing.h b/third_party/blink/renderer/core/timing/performance_resource_timing.h
index 8149bd7..5ad10e6 100644
--- a/third_party/blink/renderer/core/timing/performance_resource_timing.h
+++ b/third_party/blink/renderer/core/timing/performance_resource_timing.h
@@ -113,8 +113,14 @@
   bool CrossOriginIsolatedCapability() const {
     return cross_origin_isolated_capability_;
   }
+  mojom::blink::CacheState CacheState() const { return cache_state_; }
+  static uint64_t GetTransferSize(uint64_t encoded_body_size,
+                                  mojom::blink::CacheState cache_state);
 
  private:
+  // https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-transfersize
+  static const size_t kHeaderSize = 300;
+
   AtomicString GetNextHopProtocol(const AtomicString& alpn_negotiated_protocol,
                                   const AtomicString& connection_info) const;
 
@@ -139,7 +145,7 @@
       mojom::blink::RequestContextType::UNSPECIFIED;
   network::mojom::RequestDestination request_destination_ =
       network::mojom::RequestDestination::kEmpty;
-  uint64_t transfer_size_ = 0;
+  mojom::blink::CacheState cache_state_ = mojom::blink::CacheState::kNone;
   uint64_t encoded_body_size_ = 0;
   uint64_t decoded_body_size_ = 0;
   bool did_reuse_connection_ = false;
diff --git a/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc b/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
index d8aeb77..1873d10a 100644
--- a/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
+++ b/third_party/blink/renderer/core/workers/worklet_module_tree_client.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/script/module_script.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
 #include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
diff --git a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
index 1817d07..0fba4da4 100644
--- a/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
+++ b/third_party/blink/renderer/modules/ad_auction/navigator_auction.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_auction_ad.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_auction_ad_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_auction_ad_interest_group.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA b/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA
index 44110182..d83a533 100644
--- a/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA
+++ b/third_party/blink/renderer/modules/broadcastchannel/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Blink>Messaging"
 }
-team_email: "platform-architecture-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 9213a22..2d0e49b 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -2046,6 +2046,7 @@
     ExceptionState& exception_state) const {
   ImageData::ValidateAndCreateParams params;
   params.context_2d_error_mode = true;
+  params.default_color_space = GetCanvas2DColorParams().ColorSpace();
   return ImageData::ValidateAndCreate(std::abs(sw), std::abs(sh), absl::nullopt,
                                       image_data_settings, params,
                                       exception_state);
@@ -2115,6 +2116,8 @@
 
   ImageData::ValidateAndCreateParams validate_and_create_params;
   validate_and_create_params.context_2d_error_mode = true;
+  validate_and_create_params.default_color_space =
+      GetCanvas2DColorParams().ColorSpace();
 
   if (!CanCreateCanvas2dResourceProvider() || isContextLost()) {
     return ImageData::ValidateAndCreate(
diff --git a/third_party/blink/renderer/modules/service_worker/fetch_event.cc b/third_party/blink/renderer/modules/service_worker/fetch_event.cc
index 00d5d20..3bab1f7 100644
--- a/third_party/blink/renderer/modules/service_worker/fetch_event.cc
+++ b/third_party/blink/renderer/modules/service_worker/fetch_event.cc
@@ -225,8 +225,6 @@
   info->SetLoadResponseEnd(completion_time);
   info->SetInitialURL(request_->url());
   info->SetFinalResponse(resource_response);
-  info->AddFinalTransferSize(encoded_data_length == -1 ? 0
-                                                       : encoded_data_length);
   WorkerGlobalScopePerformance::performance(*worker_global_scope)
       ->GenerateAndAddResourceTiming(*info);
 }
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.cc b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
index cf91500..4b98ae5e 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.cc
@@ -102,10 +102,13 @@
   KURL page_url = source->GetPageUrl();
   String source_id = areas_->at(source);
   String source_string = PackSource(page_url, source_id);
-  remote_area_->Put(StringToUint8Vector(key, GetKeyFormat()),
-                    StringToUint8Vector(value, value_format),
-                    optional_old_value, source_string,
-                    MakeSuccessCallback(source));
+
+  if (!is_session_storage_for_prerendering_) {
+    remote_area_->Put(StringToUint8Vector(key, GetKeyFormat()),
+                      StringToUint8Vector(value, value_format),
+                      optional_old_value, source_string,
+                      MakeSuccessCallback(source));
+  }
   if (!IsSessionStorage())
     EnqueuePendingMutation(key, value, old_value, source_string);
   else if (old_value != value)
@@ -127,9 +130,11 @@
   KURL page_url = source->GetPageUrl();
   String source_id = areas_->at(source);
   String source_string = PackSource(page_url, source_id);
-  remote_area_->Delete(StringToUint8Vector(key, GetKeyFormat()),
-                       optional_old_value, source_string,
-                       MakeSuccessCallback(source));
+  if (!is_session_storage_for_prerendering_) {
+    remote_area_->Delete(StringToUint8Vector(key, GetKeyFormat()),
+                         optional_old_value, source_string,
+                         MakeSuccessCallback(source));
+  }
   if (!IsSessionStorage())
     EnqueuePendingMutation(key, String(), old_value, source_string);
   else
@@ -164,8 +169,10 @@
   KURL page_url = source->GetPageUrl();
   String source_id = areas_->at(source);
   String source_string = PackSource(page_url, source_id);
-  remote_area_->DeleteAll(source_string, std::move(new_observer),
-                          MakeSuccessCallback(source));
+  if (!is_session_storage_for_prerendering_) {
+    remote_area_->DeleteAll(source_string, std::move(new_observer),
+                            MakeSuccessCallback(source));
+  }
   if (!IsSessionStorage())
     EnqueuePendingMutation(String(), String(), String(), source_string);
   else if (!already_empty)
@@ -182,10 +189,12 @@
     AreaType type,
     scoped_refptr<const SecurityOrigin> origin,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-    StorageNamespace* storage_namespace)
+    StorageNamespace* storage_namespace,
+    bool is_session_storage_for_prerendering)
     : type_(type),
       origin_(std::move(origin)),
       storage_namespace_(storage_namespace),
+      is_session_storage_for_prerendering_(is_session_storage_for_prerendering),
       task_runner_(std::move(task_runner)),
       areas_(MakeGarbageCollected<HeapHashMap<WeakMember<Source>, String>>()) {
   BindStorageArea();
@@ -218,6 +227,7 @@
 
 void CachedStorageArea::ResetConnection(
     mojo::PendingRemote<mojom::blink::StorageArea> new_area) {
+  DCHECK(!is_session_storage_for_prerendering_);
   remote_area_.reset();
   BindStorageArea(std::move(new_area));
 
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area.h b/third_party/blink/renderer/modules/storage/cached_storage_area.h
index 9196428d..68caa52 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area.h
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area.h
@@ -63,7 +63,8 @@
   CachedStorageArea(AreaType type,
                     scoped_refptr<const SecurityOrigin> origin,
                     scoped_refptr<base::SingleThreadTaskRunner> ipc_runner,
-                    StorageNamespace* storage_namespace);
+                    StorageNamespace* storage_namespace,
+                    bool is_session_storage_for_prerendering);
 
   // These correspond to blink::Storage.
   unsigned GetLength();
@@ -97,6 +98,10 @@
   void ResetConnection(
       mojo::PendingRemote<mojom::blink::StorageArea> new_area = {});
 
+  bool is_session_storage_for_prerendering() const {
+    return is_session_storage_for_prerendering_;
+  }
+
   void SetRemoteAreaForTesting(
       mojo::PendingRemote<mojom::blink::StorageArea> area) {
     remote_area_.Bind(std::move(area));
@@ -177,6 +182,12 @@
   const AreaType type_;
   const scoped_refptr<const SecurityOrigin> origin_;
   const WeakPersistent<StorageNamespace> storage_namespace_;
+  // Session storage state for prerendering is initialized by cloning the
+  // primary session storage state. It is used locally by the prerendering
+  // context, and does not get propagated back to the primary state (i.e., via
+  // remote_area_). For more details:
+  // https://docs.google.com/document/d/1I5Hr8I20-C1GBr4tAXdm0U8a1RDUKHt4n7WcH4fxiSE/edit?usp=sharing
+  const bool is_session_storage_for_prerendering_;
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   std::unique_ptr<StorageAreaMap> map_;
diff --git a/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc b/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc
index b434607..8299784 100644
--- a/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc
+++ b/third_party/blink/renderer/modules/storage/cached_storage_area_test.cc
@@ -38,7 +38,7 @@
                            : CachedStorageArea::AreaType::kLocalStorage;
     cached_area_ = base::MakeRefCounted<CachedStorageArea>(
         area_type, kOrigin, scheduler::GetSingleThreadTaskRunnerForTesting(),
-        nullptr);
+        nullptr, /*is_session_storage_for_prerendering=*/false);
     cached_area_->SetRemoteAreaForTesting(
         mock_storage_area_.GetInterfaceRemote());
     source_area_ = MakeGarbageCollected<FakeAreaSource>(kPageUrl);
diff --git a/third_party/blink/renderer/modules/storage/dom_window_storage.cc b/third_party/blink/renderer/modules/storage/dom_window_storage.cc
index 6723295..9888455 100644
--- a/third_party/blink/renderer/modules/storage/dom_window_storage.cc
+++ b/third_party/blink/renderer/modules/storage/dom_window_storage.cc
@@ -90,10 +90,16 @@
       StorageNamespace::From(window->GetFrame()->GetPage());
   if (!storage_namespace)
     return nullptr;
-  auto storage_area =
-      storage_namespace->GetCachedArea(window->GetSecurityOrigin());
+  scoped_refptr<CachedStorageArea> cached_storage_area;
+  if (window->document()->IsPrerendering()) {
+    cached_storage_area = storage_namespace->CreateCachedAreaForPrerender(
+        window->GetSecurityOrigin());
+  } else {
+    cached_storage_area =
+        storage_namespace->GetCachedArea(window->GetSecurityOrigin());
+  }
   session_storage_ =
-      StorageArea::Create(window, std::move(storage_area),
+      StorageArea::Create(window, std::move(cached_storage_area),
                           StorageArea::StorageType::kSessionStorage);
 
   if (!session_storage_->CanAccessStorage()) {
diff --git a/third_party/blink/renderer/modules/storage/storage_area.cc b/third_party/blink/renderer/modules/storage/storage_area.cc
index 32373c8..a40cd63 100644
--- a/third_party/blink/renderer/modules/storage/storage_area.cc
+++ b/third_party/blink/renderer/modules/storage/storage_area.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/modules/storage/storage_namespace.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -73,6 +74,11 @@
   DCHECK(window);
   DCHECK(cached_area_);
   cached_area_->RegisterSource(this);
+  if (cached_area_->is_session_storage_for_prerendering()) {
+    DomWindow()->document()->AddWillDispatchPrerenderingchangeCallback(
+        WTF::Bind(&StorageArea::OnDocumentActivatedForPrerendering,
+                  WrapWeakPersistent(this)));
+  }
 }
 
 unsigned StorageArea::length(ExceptionState& exception_state) const {
@@ -246,4 +252,18 @@
       ->CreateWebScopedVirtualTimePauser(name, duration);
 }
 
+void StorageArea::OnDocumentActivatedForPrerendering() {
+  StorageNamespace* storage_namespace =
+      StorageNamespace::From(DomWindow()->GetFrame()->GetPage());
+  if (!storage_namespace)
+    return;
+
+  // Swap out the session storage state used within prerendering, and replace it
+  // with the normal session storage state. For more details:
+  // https://docs.google.com/document/d/1I5Hr8I20-C1GBr4tAXdm0U8a1RDUKHt4n7WcH4fxiSE/edit?usp=sharing
+  cached_area_ =
+      storage_namespace->GetCachedArea(DomWindow()->GetSecurityOrigin());
+  cached_area_->RegisterSource(this);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/storage/storage_area.h b/third_party/blink/renderer/modules/storage/storage_area.h
index 941e2bd..698c270c 100644
--- a/third_party/blink/renderer/modules/storage/storage_area.h
+++ b/third_party/blink/renderer/modules/storage/storage_area.h
@@ -92,7 +92,10 @@
 
  private:
   void RecordModificationInMetrics();
-  const scoped_refptr<CachedStorageArea> cached_area_;
+
+  void OnDocumentActivatedForPrerendering();
+
+  scoped_refptr<CachedStorageArea> cached_area_;
   StorageType storage_type_;
   const bool should_enqueue_events_;
 
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.cc b/third_party/blink/renderer/modules/storage/storage_namespace.cc
index b10a0f2..3827a9a 100644
--- a/third_party/blink/renderer/modules/storage/storage_namespace.cc
+++ b/third_party/blink/renderer/modules/storage/storage_namespace.cc
@@ -100,11 +100,23 @@
   result = base::MakeRefCounted<CachedStorageArea>(
       IsSessionStorage() ? CachedStorageArea::AreaType::kSessionStorage
                          : CachedStorageArea::AreaType::kLocalStorage,
-      origin, controller_->TaskRunner(), this);
+      origin, controller_->TaskRunner(), this,
+      /*is_session_storage_for_prerendering=*/false);
   cached_areas_.insert(std::move(origin), result);
   return result;
 }
 
+scoped_refptr<CachedStorageArea> StorageNamespace::CreateCachedAreaForPrerender(
+    const SecurityOrigin* origin_ptr) {
+  DCHECK((IsSessionStorage()));
+  scoped_refptr<const SecurityOrigin> origin(origin_ptr);
+  return base::MakeRefCounted<CachedStorageArea>(
+      IsSessionStorage() ? CachedStorageArea::AreaType::kSessionStorage
+                         : CachedStorageArea::AreaType::kLocalStorage,
+      origin, controller_->TaskRunner(), this,
+      /*is_session_storage_for_prerendering=*/true);
+}
+
 void StorageNamespace::CloneTo(const String& target) {
   DCHECK(IsSessionStorage()) << "Cannot clone a local storage namespace.";
   EnsureConnected();
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace.h b/third_party/blink/renderer/modules/storage/storage_namespace.h
index bb62188..ec36582 100644
--- a/third_party/blink/renderer/modules/storage/storage_namespace.h
+++ b/third_party/blink/renderer/modules/storage/storage_namespace.h
@@ -84,6 +84,9 @@
 
   scoped_refptr<CachedStorageArea> GetCachedArea(const SecurityOrigin* origin);
 
+  scoped_refptr<CachedStorageArea> CreateCachedAreaForPrerender(
+      const SecurityOrigin* origin);
+
   // Only valid to call this if |this| and |target| are session storage
   // namespaces.
   void CloneTo(const String& target);
diff --git a/third_party/blink/renderer/modules/webcodecs/parsed_read_into_options.cc b/third_party/blink/renderer/modules/webcodecs/parsed_read_into_options.cc
index c06ebf3..8506ebb 100644
--- a/third_party/blink/renderer/modules/webcodecs/parsed_read_into_options.cc
+++ b/third_party/blink/renderer/modules/webcodecs/parsed_read_into_options.cc
@@ -7,9 +7,9 @@
 #include <algorithm>
 
 #include "base/numerics/checked_math.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_region.h"
 #include "third_party/blink/renderer/modules/webcodecs/plane_layout.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_read_into_options.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame_region.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
index 528c51b..ae87cbf0 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_decoder.cc
@@ -24,12 +24,12 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_encoded_video_chunk.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_config.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_video_decoder_support.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_region.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/modules/webcodecs/codec_config_eval.h"
 #include "third_party/blink/renderer/modules/webcodecs/encoded_video_chunk.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_decoder_broker.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame_region.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/bindings/script_state.h"
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.h b/third_party/blink/renderer/modules/webcodecs/video_frame.h
index 55b4efd..c90d6574 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.h
@@ -10,13 +10,13 @@
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_typedefs.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_typedefs.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_video_frame_region.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_image_source.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap_source.h"
 #include "third_party/blink/renderer/modules/canvas/canvas2d/canvas_image_source_util.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/webcodecs/plane.h"
 #include "third_party/blink/renderer/modules/webcodecs/video_frame_handle.h"
-#include "third_party/blink/renderer/modules/webcodecs/video_frame_region.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
diff --git a/third_party/blink/renderer/platform/exported/web_url_response.cc b/third_party/blink/renderer/platform/exported/web_url_response.cc
index a6f3128..a67bba83 100644
--- a/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -434,6 +434,10 @@
   resource_response_->SetAddressSpace(remote_ip_address_space);
 }
 
+void WebURLResponse::SetIsValidated(bool is_validated) {
+  resource_response_->SetIsValidated(is_validated);
+}
+
 void WebURLResponse::SetEncodedDataLength(int64_t length) {
   resource_response_->SetEncodedDataLength(length);
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 7838cf4..bf6609a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -275,20 +275,13 @@
 
 void PopulateAndAddResourceTimingInfo(Resource* resource,
                                       scoped_refptr<ResourceTimingInfo> info,
-                                      base::TimeTicks response_end,
-                                      int64_t encoded_data_length) {
+                                      base::TimeTicks response_end) {
   info->SetInitialURL(
       resource->GetResourceRequest().GetRedirectInfo().has_value()
           ? resource->GetResourceRequest().GetRedirectInfo()->original_url
           : resource->GetResourceRequest().Url());
   info->SetFinalResponse(resource->GetResponse());
   info->SetLoadResponseEnd(response_end);
-  // encodedDataLength == -1 means "not available".
-  // TODO(ricea): Find cases where it is not available but the
-  // PerformanceResourceTiming spec requires it to be available and fix
-  // them.
-  info->AddFinalTransferSize(encoded_data_length == -1 ? 0
-                                                       : encoded_data_length);
 }
 
 }  // namespace
@@ -1863,8 +1856,7 @@
   if (scoped_refptr<ResourceTimingInfo> info =
           resource_timing_info_map_.Take(resource)) {
     if (resource->GetResponse().IsHTTP()) {
-      PopulateAndAddResourceTimingInfo(resource, info, response_end,
-                                       encoded_data_length);
+      PopulateAndAddResourceTimingInfo(resource, info, response_end);
       auto receiver = Context().TakePendingWorkerTimingReceiver(
           resource->GetResponse().RequestId());
       info->SetWorkerTimingReceiver(std::move(receiver));
@@ -1911,9 +1903,7 @@
 
   if (scoped_refptr<ResourceTimingInfo> info =
           resource_timing_info_map_.Take(resource)) {
-    PopulateAndAddResourceTimingInfo(
-        resource, info, finish_time,
-        resource->GetResponse().EncodedDataLength());
+    PopulateAndAddResourceTimingInfo(resource, info, finish_time);
     if (resource->Options().request_initiator_context == kDocumentContext)
       Context().AddResourceTiming(*info);
   }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 8233471..e04b4fa 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -86,7 +86,6 @@
 
 constexpr char kTestResourceFilename[] = "white-1x1.png";
 constexpr char kTestResourceMimeType[] = "image/png";
-constexpr uint32_t kTestResourceSize = 103;  // size of white-1x1.png
 
 const FetchClientSettingsObjectSnapshot& CreateFetchClientSettingsObject(
     network::mojom::IPAddressSpace address_space) {
@@ -572,20 +571,6 @@
   new_resource->Loader()->Cancel();
 }
 
-TEST_F(ResourceFetcherTest, ResourceTimingInfo) {
-  auto info = ResourceTimingInfo::Create(
-      fetch_initiator_type_names::kDocument, base::TimeTicks::Now(),
-      mojom::blink::RequestContextType::UNSPECIFIED,
-      network::mojom::RequestDestination::kEmpty);
-  info->AddFinalTransferSize(5);
-  EXPECT_EQ(info->TransferSize(), static_cast<uint64_t>(5));
-  ResourceResponse redirect_response(KURL("https://example.com/original"));
-  redirect_response.SetHttpStatusCode(200);
-  redirect_response.SetEncodedDataLength(7);
-  info->AddRedirect(redirect_response, KURL("https://example.com/redirect"));
-  EXPECT_EQ(info->TransferSize(), static_cast<uint64_t>(12));
-}
-
 TEST_F(ResourceFetcherTest, VaryOnBack) {
   scoped_refptr<const SecurityOrigin> source_origin =
       SecurityOrigin::CreateUniqueOpaque();
@@ -854,50 +839,6 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedMockRedirectRequester);
 };
 
-TEST_F(ResourceFetcherTest, SameOriginRedirect) {
-  const char kRedirectURL[] = "http://127.0.0.1:8000/redirect.html";
-  const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
-  MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
-  ScopedMockRedirectRequester requester(platform_->GetURLLoaderMockFactory(),
-                                        context, CreateTaskRunner());
-  requester.RegisterRedirect(kRedirectURL, kFinalURL);
-  requester.RegisterFinalResource(kFinalURL);
-  requester.Request(kRedirectURL);
-
-  EXPECT_EQ(kRedirectResponseOverheadBytes + kTestResourceSize,
-            context->GetTransferSize());
-}
-
-TEST_F(ResourceFetcherTest, CrossOriginRedirect) {
-  const char kRedirectURL[] = "http://otherorigin.test/redirect.html";
-  const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
-  MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
-  ScopedMockRedirectRequester requester(platform_->GetURLLoaderMockFactory(),
-                                        context, CreateTaskRunner());
-  requester.RegisterRedirect(kRedirectURL, kFinalURL);
-  requester.RegisterFinalResource(kFinalURL);
-  requester.Request(kRedirectURL);
-
-  EXPECT_EQ(kTestResourceSize, context->GetTransferSize());
-}
-
-TEST_F(ResourceFetcherTest, ComplexCrossOriginRedirect) {
-  const char kRedirectURL1[] = "http://127.0.0.1:8000/redirect1.html";
-  const char kRedirectURL2[] = "http://otherorigin.test/redirect2.html";
-  const char kRedirectURL3[] = "http://127.0.0.1:8000/redirect3.html";
-  const char kFinalURL[] = "http://127.0.0.1:8000/final.html";
-  MockFetchContext* context = MakeGarbageCollected<MockFetchContext>();
-  ScopedMockRedirectRequester requester(platform_->GetURLLoaderMockFactory(),
-                                        context, CreateTaskRunner());
-  requester.RegisterRedirect(kRedirectURL1, kRedirectURL2);
-  requester.RegisterRedirect(kRedirectURL2, kRedirectURL3);
-  requester.RegisterRedirect(kRedirectURL3, kFinalURL);
-  requester.RegisterFinalResource(kFinalURL);
-  requester.Request(kRedirectURL1);
-
-  EXPECT_EQ(kTestResourceSize, context->GetTransferSize());
-}
-
 TEST_F(ResourceFetcherTest, SynchronousRequest) {
   KURL url("http://127.0.0.1:8000/foo.png");
   RegisterMockedURLLoad(url);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
index 126e82d9..c8e8f73 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.cc
@@ -474,6 +474,17 @@
       connection_info_string.length());
 }
 
+mojom::blink::CacheState ResourceResponse::CacheState() const {
+  return is_validated_
+             ? mojom::blink::CacheState::kValidated
+             : (!encoded_data_length_ ? mojom::blink::CacheState::kLocal
+                                      : mojom::blink::CacheState::kNone);
+}
+
+void ResourceResponse::SetIsValidated(bool is_validated) {
+  is_validated_ = is_validated;
+}
+
 void ResourceResponse::SetEncodedDataLength(int64_t value) {
   encoded_data_length_ = value;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index 8326b7e..2cd78af 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -37,6 +37,7 @@
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/renderer/platform/network/http_header_map.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
@@ -430,6 +431,9 @@
 
   AtomicString ConnectionInfoString() const;
 
+  mojom::blink::CacheState CacheState() const;
+  void SetIsValidated(bool is_validated);
+
   int64_t EncodedDataLength() const { return encoded_data_length_; }
   void SetEncodedDataLength(int64_t value);
 
@@ -678,6 +682,9 @@
   net::HttpResponseInfo::ConnectionInfo connection_info_ =
       net::HttpResponseInfo::ConnectionInfo::CONNECTION_INFO_UNKNOWN;
 
+  // Whether the resource came from the cache and validated over the network.
+  bool is_validated_ = false;
+
   // Size of the response in bytes prior to decompression.
   int64_t encoded_data_length_ = 0;
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
index 2b67a18e..f07c415 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.cc
@@ -12,17 +12,6 @@
 void ResourceTimingInfo::AddRedirect(const ResourceResponse& redirect_response,
                                      const KURL& new_url) {
   redirect_chain_.push_back(redirect_response);
-  if (has_cross_origin_redirect_)
-    return;
-  bool cross_origin = !SecurityOrigin::AreSameOrigin(
-      redirect_response.CurrentRequestUrl(), new_url);
-  if (cross_origin) {
-    has_cross_origin_redirect_ = true;
-    transfer_size_ = 0;
-  } else {
-    DCHECK_GE(redirect_response.EncodedDataLength(), 0);
-    transfer_size_ += redirect_response.EncodedDataLength();
-  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
index 5d0cb5c4..825ef805 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h
@@ -35,6 +35,7 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
+#include "third_party/blink/public/mojom/timing/resource_timing.mojom-blink.h"
 #include "third_party/blink/public/mojom/timing/worker_timing_container.mojom-blink.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
@@ -78,10 +79,9 @@
     return redirect_chain_;
   }
 
-  void AddFinalTransferSize(uint64_t encoded_data_length) {
-    transfer_size_ += encoded_data_length;
+  mojom::blink::CacheState CacheState() const {
+    return final_response_.CacheState();
   }
-  uint64_t TransferSize() const { return transfer_size_; }
 
   // The timestamps in PerformanceResourceTiming are measured relative from the
   // time origin. In most cases these timestamps must be positive value, so we
@@ -127,7 +127,6 @@
   KURL initial_url_;
   ResourceResponse final_response_;
   Vector<ResourceResponse> redirect_chain_;
-  uint64_t transfer_size_ = 0;
   bool has_cross_origin_redirect_ = false;
   bool negative_allowed_ = false;
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
index ad407ff..b50689f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/web_url_loader.cc
@@ -842,6 +842,7 @@
   response->SetCorsExposedHeaderNames(cors_exposed_header_names);
   response->SetDidServiceWorkerNavigationPreload(
       head.did_service_worker_navigation_preload);
+  response->SetIsValidated(head.is_validated);
   response->SetEncodedDataLength(head.encoded_data_length);
   response->SetEncodedBodyLength(head.encoded_body_length);
   response->SetWasAlpnNegotiated(head.was_alpn_negotiated);
diff --git a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
index ed126f7..1c1efe0 100644
--- a/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/url_loader/worker_main_script_loader.cc
@@ -177,12 +177,9 @@
       ResourceTimingInfo::Create(g_empty_atom, base::TimeTicks::Now(),
                                  initial_request_.GetRequestContext(),
                                  initial_request_.GetRequestDestination());
-  const int64_t encoded_data_length = resource_response_.EncodedDataLength();
   timing_info->SetInitialURL(initial_request_url_);
   timing_info->SetFinalResponse(resource_response_);
   timing_info->SetLoadResponseEnd(status.completion_time);
-  timing_info->AddFinalTransferSize(
-      encoded_data_length == -1 ? 0 : encoded_data_length);
   fetch_context_->AddResourceTiming(*timing_info);
 
   has_received_completion_ = true;
diff --git a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
index 61b4e55..b579b27a 100644
--- a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
@@ -36,8 +36,6 @@
   MockFetchContext() = default;
   ~MockFetchContext() override = default;
 
-  uint64_t GetTransferSize() const { return transfer_size_; }
-
   void set_blocked_urls(Vector<String> blocked_urls) {
     blocked_urls_ = std::move(blocked_urls);
   }
@@ -85,7 +83,6 @@
   }
   void AddResourceTiming(
       const ResourceTimingInfo& resource_timing_info) override {
-    transfer_size_ = resource_timing_info.TransferSize();
   }
   std::unique_ptr<ResourceLoadInfoNotifierWrapper>
   CreateResourceLoadInfoNotifierWrapper() override {
@@ -116,7 +113,6 @@
   }
 
  private:
-  uint64_t transfer_size_ = 0;
   mojom::ResourceLoadInfoNotifier* resource_load_info_notifier_ = nullptr;
   std::unique_ptr<WeakWrapperResourceLoadInfoNotifier>
       weak_wrapper_resource_load_info_notifier_;
diff --git a/third_party/blink/renderer/platform/wtf/text/DIR_METADATA b/third_party/blink/renderer/platform/wtf/text/DIR_METADATA
deleted file mode 100644
index 23763da..0000000
--- a/third_party/blink/renderer/platform/wtf/text/DIR_METADATA
+++ /dev/null
@@ -1,4 +0,0 @@
-monorail {
-  component: "Blink>Internals>WTF"
-}
-team_email: "platform-architecture-dev@chromium.org"
\ No newline at end of file
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 174e1fd3..6a594f57 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2490,6 +2490,24 @@
 crbug.com/958381 [ Mac ] external/wpt/css/CSS2/tables/table-anonymous-objects-206.xht [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/protocol/split.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-video.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDTMFSender-insertDTMF.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCRtpSender-replaceTrack.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-encoded-transform/RTCEncodedVideoFrame-serviceworker-failure.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCPeerConnection-connectionState.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCDataChannel-close.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-worker.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/simulcast/vp8.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/protocol/handover-datachannel.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/simulcast/setParameters-active.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-errors.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-connectionState.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCPeerConnection-helper-test.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/protocol/candidate-exchange.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/protocol/bundle.https.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-svc/RTCRtpParameters-scalability.html [ Timeout ]
+crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ]
 crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc-encoded-transform/RTCPeerConnection-insertable-streams-video-frames.https.html [ Timeout ]
 crbug.com/626703 [ Mac11.0 ] external/wpt/webrtc/protocol/crypto-suite.https.html [ Timeout ]
 crbug.com/626703 [ Mac11.0 ] virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCDataChannel-bufferedAmount.html [ Timeout ]
@@ -6868,10 +6886,6 @@
 crbug.com/1206108 external/wpt/pointerevents/pointerevent_click_is_a_pointerevent_multiple_clicks.html?touch [ Failure Pass ]
 
 # Some plzServiceWorker and plzDedicatedWorker singled out from generic sheriff rounds above
-crbug.com/1207849 virtual/plz-service-worker/external/wpt/service-workers/service-worker/no-dynamic-import-in-module.any.serviceworker-module.html [ Pass Failure Crash ]
-
-crbug.com/1207851 virtual/plz-service-worker/external/wpt/service-workers/idlharness.https.any.sharedworker.html [ Pass Failure Timeout ]
-crbug.com/1207851 virtual/plz-service-worker/external/wpt/service-workers/idlharness.https.any.serviceworker.html [ Pass Failure Timeout ]
 crbug.com/1207851 virtual/plz-dedicated-worker/external/wpt/service-workers/idlharness.https.any.serviceworker.html [ Pass Failure Timeout ]
 
 # Sheriff 2021-05-10
diff --git a/third_party/blink/web_tests/css3/flexbox/DIR_METADATA b/third_party/blink/web_tests/css3/flexbox/DIR_METADATA
index 16e4e2d6f..dd6dafd 100644
--- a/third_party/blink/web_tests/css3/flexbox/DIR_METADATA
+++ b/third_party/blink/web_tests/css3/flexbox/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Blink>Layout>Flexbox"
 }
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/css3/fonts/DIR_METADATA b/third_party/blink/web_tests/css3/fonts/DIR_METADATA
index 38e8f0f1..594a7d65 100644
--- a/third_party/blink/web_tests/css3/fonts/DIR_METADATA
+++ b/third_party/blink/web_tests/css3/fonts/DIR_METADATA
@@ -1,4 +1,3 @@
 monorail {
   component: "Blink>Fonts"
 }
-team_email: "layout-dev@chromium.org"
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
index a4b2c259..8a67b9b0 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -68553,6 +68553,19 @@
        {}
       ]
      ],
+     "dynamic-stretch-change.html": [
+      "f2fdf1b24f4acd733b0623034494e46e61d16259",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "fieldset-as-item-overflow.html": [
       "17bc82a0b51a7f76253e1ca9f75c9840abbd366f",
       [
@@ -83615,6 +83628,32 @@
        {}
       ]
      ],
+     "dynamic-grid-with-auto-fill.html": [
+      "2691674165dc72c58edfd653ae11d5b51e586525",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "dynamic-grid-within-flexbox.html": [
+      "2b8824f9940b755364aa7ab124ceea52229f5b93",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "grid-child-percent-basis-resize-1.html": [
       "7fb5d8e117d9f0b7e23bf3921843e8ea29ef4522",
       [
@@ -86338,6 +86377,19 @@
        ]
       ]
      },
+     "grid-within-flexbox-definite-change.html": [
+      "03b3e67b24ab329ebf75a2c74b1b7cf46b3a2d0d",
+      [
+       null,
+       [
+        [
+         "/css/reference/ref-filled-green-100px-square-only.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "implicit-grids": {
       "grid-support-grid-auto-columns-rows-001.html": [
        "e61ced340c610401448bdc0c636a835708fa80b9",
@@ -185773,7 +185825,7 @@
      []
     ],
     "get-host-info.sub.js": [
-     "53602a632f33873eb407ccaccb89e7837f27d9b5",
+     "9b8c2b5de63f282663cab92231fe1c35184e6f02",
      []
     ],
     "get-host-info.sub.js.headers": [
@@ -238829,7 +238881,7 @@
          []
         ],
         "transformations.yaml": [
-         "65346ca1f800f36ad35afbc4510fad56b62a3bf6",
+         "89f72468acebb64b5680f03f8a277c80d4aa8e06",
          []
         ],
         "video.yaml": [
@@ -238899,7 +238951,7 @@
          []
         ],
         "transformations.yaml": [
-         "6c439ef9cf8ac0815be24a5b314f63085fe07534",
+         "9b4cbd3463d32a094438f544440e05dbbd4ac120",
          []
         ]
        }
@@ -258096,7 +258148,7 @@
       []
      ],
      "entry-invariants.js": [
-      "462284473c0b36687739a402678a721b5a477d3b",
+      "3dc873ac157e4db8035efa2e8ca0b898b00efe3c",
       []
      ],
      "eventsource.py": [
@@ -264514,7 +264566,7 @@
       []
      ],
      "urltestdata.json": [
-      "1adea150918e9423b65b0878e44e792886fe8ec8",
+      "96c42d2284ebf75a70f51bfdb6e31966d2257edc",
       []
      ]
     },
@@ -310531,7 +310583,7 @@
       ]
      ],
      "overflow-padding.html": [
-      "963192f6f431cd073f5d8fddc2294259ad62962b",
+      "a77cac381fbee8d9ea3153d9c4ded952f85cb4cc",
       [
        null,
        {}
@@ -367486,6 +367538,13 @@
        ]
       },
       "transformations": {
+       "2d.transformation.combined.3d.transforms.html": [
+        "cff458207ce78b6e1a9c0cb5f6dbc0f1c73b06dc",
+        [
+         null,
+         {}
+        ]
+       ],
        "2d.transformation.order.html": [
         "0aa6c4a33fb3df4837947bd7e96da681281e15d7",
         [
@@ -379599,6 +379658,20 @@
        ]
       },
       "transformations": {
+       "2d.transformation.combined.3d.transforms.html": [
+        "e0987b4bb29859abe6199a499f282651786c257a",
+        [
+         null,
+         {}
+        ]
+       ],
+       "2d.transformation.combined.3d.transforms.worker.js": [
+        "d3a2d1e03607836f0accfc7b9d566965fcfdb336",
+        [
+         "html/canvas/offscreen/transformations/2d.transformation.combined.3d.transforms.worker.html",
+         {}
+        ]
+       ],
        "2d.transformation.order.html": [
         "127472dde11607f5966d3a4ce7f62ebc42e0f5fe",
         [
@@ -426660,15 +426733,15 @@
       {}
      ]
     ],
-    "TAO-crossorigin-port.sub.html": [
-     "0601217d0ae3a7bc057853dd23901650ccfe4633",
+    "TAO-null-opaque-origin.html": [
+     "6548a7b9ad437407eaded2c6efc4974dec242ecd",
      [
       null,
       {}
      ]
     ],
-    "TAO-null-opaque-origin.html": [
-     "6548a7b9ad437407eaded2c6efc4974dec242ecd",
+    "TAO-port-mismatch-means-crossorigin.html": [
+     "1d8b69c8e9b34275e317c8bd348a42725b213cfa",
      [
       null,
       {}
@@ -445080,7 +445153,7 @@
      ]
     ],
     "failure.html": [
-     "8f3d0299a40fdbff76e286cf45bc739cf2f3cf84",
+     "c22357b6c10749744ff079a84ab0f1e2c7c7f1b7",
      [
       null,
       {
@@ -472994,7 +473067,7 @@
        ]
       ],
       "002.worker.js": [
-       "8eb41c23fdcfc2a81a135582648b93ebfde40d22",
+       "d4f48354eda302ba0d912649c2b9af70aae0d54e",
        [
         "workers/semantics/interface-objects/002.worker.html",
         {}
diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/CSS2/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/CSS2/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/CSS2/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-align/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-align/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-align/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-break/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-break/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-break/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-break/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-cascade/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-cascade/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-cascade/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-color/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-color/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-color/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-conditional/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-conditional/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-conditional/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-contain/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-display/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-display/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-flexbox/DIR_METADATA
index aeed0e5..e51f58e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-flexbox/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Flexbox"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-font-loading/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-font-loading/DIR_METADATA
index 729d4e2..79a21de 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-font-loading/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-font-loading/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail {
   component: "Blink>Fonts"
 }
-team_email: "layout-dev@chromium.org"
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-fonts/DIR_METADATA
index 729d4e2..79a21de 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-fonts/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail {
   component: "Blink>Fonts"
 }
-team_email: "layout-dev@chromium.org"
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-grid/DIR_METADATA
index 00b116ef2..0a52f7ca 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Grid"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-layout-api/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-layout-api/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-layout-api/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-layout-api/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-logical/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-logical/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-logical/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-logical/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-multicol/DIR_METADATA
index e6cb0fe2..d7aaf3d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-multicol/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>MultiCol"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-namespaces/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-namespaces/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-namespaces/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-padding.html b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-padding.html
index 963192f..a77cac3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-padding.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-overflow/overflow-padding.html
@@ -84,10 +84,10 @@
 </div>
 <script>
   function hasHorizontalScrollbar(el) {
-    return (el.offsetHeight - el.clientHeight) > 0;
+    return (el.scrollWidth - el.offsetWidth) > 0;
   }
   function hasVerticalScrollbar(el) {
-    return (el.offsetWidth - el.clientWidth) > 0;
+    return (el.scrollHeight - el.offsetHeight) > 0;
   }
   // Tests needs to be run after load.
   function runTest() {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-position/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-position/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/DIR_METADATA
index 275a430..b195043 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/DIR_METADATA
@@ -1,7 +1,3 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scoping/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-scoping/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-scoping/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA
index 54b56f5..2a19761 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Shape"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-syntax/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA
index 4f37329..b0e99529 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Table"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-timing/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-ui/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-values/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-variables/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA
index ff55dc9..6d01f16 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>WritingMode"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-writing-modes/vrl-inline-paint-invalidation.html b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/vrl-inline-paint-invalidation.html
new file mode 100644
index 0000000..a804e4d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-writing-modes/vrl-inline-paint-invalidation.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1206914">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<link rel="stylesheet" href="/fonts/ahem.css">
+<script src="/common/reftest-wait.js"></script>
+<script src="/common/rendering-utils.js"></script>
+<p>Test passes if there is a filled green square.</p>
+<div id="target" style="font: 100px/1 Ahem; color: green; width: 50px; height: 100px; writing-mode: vertical-rl; line-height: 0; background: red;">
+  <div style="width: 100%;">
+    <span style="position: relative; left: -50px;">X</span>
+  </div>
+</div>
+<script>
+waitForAtLeastOneFrame().then(function() {
+  document.getElementById('target').style.width = '100px';
+  takeScreenshot();
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom-view/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/cssom/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/mediaqueries/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/motion/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA
deleted file mode 100644
index 7bdd904..0000000
--- a/third_party/blink/web_tests/external/wpt/css/selectors/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail {
-  component: "Blink>CSS"
-}
-team_email: "layout-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA
index aab9ded..97e2659 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA
index aeed0e5..e51f58e 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Flexbox"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA
index 54b56f5..2a19761 100644
--- a/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/DIR_METADATA
@@ -1,7 +1,6 @@
 monorail {
   component: "Blink>Layout>Shape"
 }
-team_email: "layout-dev@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/documents/dom-tree-accessors/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/dom/documents/dom-tree-accessors/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/documents/dom-tree-accessors/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/elements-in-the-dom/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/dom/elements/elements-in-the-dom/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/elements/elements-in-the-dom/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/dom/elements/global-attributes/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/common-dom-interfaces/collections/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/conformance-requirements/extensibility/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/infrastructure/conformance-requirements/extensibility/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/conformance-requirements/extensibility/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/infrastructure/terminology/plugins/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/infrastructure/terminology/plugins/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/infrastructure/terminology/plugins/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/other-elements-attributes-and-apis/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-select-element-0/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-select-element-0/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-select-element-0/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-textarea-element-0/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-textarea-element-0/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/rendering/bindings/the-textarea-element-0/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/semantics/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-html-fragments/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/syntax/serializing-xml-fragments/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/closing-the-input-stream/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-write/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/document-writeln/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/event-loops/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/events/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA b/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA
deleted file mode 100644
index 9e1f16642..0000000
--- a/third_party/blink/web_tests/external/wpt/html/webappapis/scripting/processing-model-2/DIR_METADATA
+++ /dev/null
@@ -1,2 +0,0 @@
-team_email: "dom-dev@chromium.org"
-
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA b/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
index c7280ce..b195043 100644
--- a/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/DIR_METADATA
@@ -1,7 +1,3 @@
-monorail {
-  component: "Blink>Infra>Ecosystem"
-}
-team_email: "ecosystem-infra@chromium.org"
 wpt {
   notify: YES
 }
diff --git a/third_party/blink/web_tests/external/wpt/lint.ignore b/third_party/blink/web_tests/external/wpt/lint.ignore
index 9f1cb6e7..525b46b 100644
--- a/third_party/blink/web_tests/external/wpt/lint.ignore
+++ b/third_party/blink/web_tests/external/wpt/lint.ignore
@@ -487,6 +487,7 @@
 SET TIMEOUT: css/CSS2/tables/tables-102.xht
 SET TIMEOUT: css/mediaqueries/min-width-tables-001.html
 SET TIMEOUT: css/css-text/crashtests/rendering-rtl-bidi-override-crash.html
+SET TIMEOUT: resource-timing/resources/run-async-tasks-promise.js
 
 ## Build system stuff
 CSS-COLLIDING-SUPPORT-NAME: css/*/README
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
index 163f8ca..60392b8 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/TAOResponse.py
@@ -1,8 +1,12 @@
+import os
+
 def main(request, response):
-    origin = request.headers[b'origin']
-    response.headers.set(b'Access-Control-Allow-Origin', origin)
+    if b'origin' in request.headers:
+      origin = request.headers[b'origin']
+      response.headers.set(b'Access-Control-Allow-Origin', origin)
 
     tao = request.GET.first(b'tao')
+    img = request.GET.first(b'img') if b'img' in request.GET else None
 
     if tao == b'zero':
     # zero TAO value, fail
@@ -50,5 +54,11 @@
     else:
         pass
     response.status = 200
-    response.headers.set(b"Content-Type", b"text/plain")
-    response.content = "TEST"
+    if img:
+      response.headers.set(b"Content-Type", b"image/png")
+      with open(request.doc_root + "/resource-timing/resources/blue.png", "rb") as f:
+        response.content = f.read()
+        f.close()
+    else:
+      response.headers.set(b"Content-Type", b"text/plain")
+      response.content = "TEST"
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/cacheable-and-validated.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/cacheable-and-validated.py
new file mode 100644
index 0000000..31f0e3ab
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/cacheable-and-validated.py
@@ -0,0 +1,11 @@
+def main(request, response):
+    revalidation = 'Cache-Control' in request.headers
+    content = request.GET.first(b'content')
+    response.headers.set(b'Cache-Control', b'max-age=60')
+    response.headers.set(b'ETag', b'assdfsdfe')
+    if revalidation:
+      response.status = (304, b'NotModified')
+    else:
+      response.status = (200, b'OK');
+      response.write_status_headers()
+      response.writer.write(content);
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/redirect-cors.py b/third_party/blink/web_tests/external/wpt/resource-timing/resources/redirect-cors.py
new file mode 100644
index 0000000..ea67cb8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/redirect-cors.py
@@ -0,0 +1,10 @@
+def main(request, response):
+    location = request.GET.first(b"location")
+    response.status = 302
+    response.headers.set(b"Location", location)
+
+    if b"allow_origin" in request.GET:
+        response.headers.set(b"Access-Control-Allow-Origin", request.GET.first(b"allow_origin"))
+
+    if b"timing_allow_origin" in request.GET:
+        response.headers.set(b"Timing-Allow-Origin", request.GET.first(b"timing_allow_origin"))
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/resource-loaders.js b/third_party/blink/web_tests/external/wpt/resource-timing/resources/resource-loaders.js
index 1760628..3df07cc 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/resource-loaders.js
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/resource-loaders.js
@@ -1,8 +1,10 @@
 const load = {
   _cache_bust_value: Math.random().toString().substr(2),
+
   cache_bust: path => {
     let url = new URL(path, location.origin);
-    url.hash += `cache_bust=${load._cache_bust_value++}`;
+    url.href += (url.href.includes("?")) ? '&' : '?';
+    url.href += "unique=" + load._cache_bust_value++
     return url.href;
   },
 
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/sizes-helper.js b/third_party/blink/web_tests/external/wpt/resource-timing/resources/sizes-helper.js
new file mode 100644
index 0000000..8633668
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/sizes-helper.js
@@ -0,0 +1,16 @@
+// Header size is a fixed constant.
+// https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-transfersize
+const headerSize = 300;
+
+const cacheBustUrl = url => {
+  return url + '&unique=' + Math.random().toString().substring(2);
+}
+
+const checkSizeFields = (entry, bodySize, transferSize) => {
+  assert_equals(entry.decodedBodySize, bodySize,
+                'decodedBodySize');
+  assert_equals(entry.encodedBodySize, bodySize,
+                'encodedBodySize');
+  assert_equals(entry.transferSize, transferSize,
+                'transferSize');
+}
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/sizes-cache.any.js b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-cache.any.js
new file mode 100644
index 0000000..af70e5a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-cache.any.js
@@ -0,0 +1,55 @@
+// META: global=window,worker
+// META: script=/resource-timing/resources/sizes-helper.js
+// META: script=/resource-timing/resources/resource-loaders.js
+
+let url = new URL(
+  '/resource-timing/resources/cacheable-and-validated.py' +
+  '?content=loremipsumblablabla',
+  location.href).href;
+const bodySize = 19;
+
+const accumulateEntries = () => {
+  return new Promise(resolve => {
+    const po = new PerformanceObserver(list => {
+      resolve(list);
+    });
+    po.observe({type: "resource", buffered: true});
+  });
+};
+
+const checkResourceSizes = list => {
+  const entries = list.getEntriesByName(url);
+  assert_equals(entries.length, 3, 'Wrong number of entries');
+  let seenCount = 0;
+  for (let entry of entries) {
+    if (seenCount === 0) {
+      // 200 response
+      checkSizeFields(entry, bodySize, bodySize + headerSize);
+    } else if (seenCount === 1) {
+      // from cache
+      checkSizeFields(entry, bodySize, 0);
+    } else if (seenCount === 2) {
+      // 304 response
+      checkSizeFields(entry, bodySize, headerSize);
+    } else {
+      assert_unreached('Too many matching entries');
+    }
+    ++seenCount;
+  }
+};
+
+promise_test(() => {
+  // Use a different URL every time so that the cache behaviour does not
+  // depend on execution order.
+  url = load.cache_bust(url);
+  const eatBody = response => response.arrayBuffer();
+  const mustRevalidate = {headers: {'Cache-Control': 'max-age=0'}};
+  return fetch(url)
+    .then(eatBody)
+    .then(() => fetch(url))
+    .then(eatBody)
+    .then(() => fetch(url, mustRevalidate))
+    .then(eatBody)
+    .then(accumulateEntries)
+    .then(checkResourceSizes);
+}, 'PerformanceResourceTiming sizes caching test');
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect-img.html b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect-img.html
new file mode 100644
index 0000000..786018d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect-img.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/sizes-helper.js"></script>
+<script src="resources/resource-loaders.js"></script>
+<script src="resources/entry-invariants.js"></script>
+<script>
+// Redirects for fetch() always apply CORS rules, whereas normal resources
+// don't, so this test covers extra code paths beyond those covered by
+// resource-timing-sizes-redirect.html.
+
+const baseUrl = new URL('/resource-timing/resources/TAOResponse.py?tao=wildcard&img=true', location.href).href;
+
+const expectedSize = 1010;
+
+const hostInfo = get_host_info();
+
+const redirectUrl = (redirectSourceOrigin, targetUrl) => {
+  return redirectSourceOrigin +
+    '/resource-timing/resources/redirect-cors.py?timing_allow_origin=*' +
+    '&location=' + encodeURIComponent(targetUrl);
+};
+
+const verify_entry = entry => {
+  checkSizeFields(entry, expectedSize, expectedSize + headerSize);
+};
+
+attribute_test(load.image, baseUrl,
+  verify_entry,
+  "PerformanceResourceTiming sizes redirect image - direct URL");
+
+attribute_test(load.image,
+  redirectUrl(hostInfo.HTTP_ORIGIN, baseUrl),
+  verify_entry,
+  "PerformanceResourceTiming sizes redirect image - same origin redirect");
+
+attribute_test(load.image,
+  redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN, baseUrl),
+  verify_entry,
+  "PerformanceResourceTiming sizes redirect image - cross origin redirect");
+
+attribute_test(load.image,
+  redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
+    redirectUrl(hostInfo.HTTP_ORIGIN, baseUrl)),
+  verify_entry,
+  "PerformanceResourceTiming sizes redirect image - cross origin to same origin redirect");
+
+attribute_test(load.image,
+  redirectUrl(hostInfo.HTTP_ORIGIN,
+    redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
+      redirectUrl(hostInfo.HTTP_ORIGIN,
+        baseUrl))),
+  verify_entry,
+  "PerformanceResourceTiming sizes redirect image - same origin to remote " +
+  "origin to same origin redirect");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect.any.js b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect.any.js
new file mode 100644
index 0000000..e483a4d4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/sizes-redirect.any.js
@@ -0,0 +1,62 @@
+// META: global=window,worker
+// META: script=/common/get-host-info.sub.js
+// META: script=/resource-timing/resources/sizes-helper.js
+
+const baseUrl =
+  new URL('/resource-timing/resources/TAOResponse.py?tao=wildcard', location.href).href;
+const expectedSize = 4;
+
+const hostInfo = get_host_info();
+performance.clearResourceTimings();
+
+const accumulateEntry = () => {
+  return new Promise(resolve => {
+    const po = new PerformanceObserver(list => {
+      resolve(list);
+    });
+    po.observe({type: "resource", buffered: true});
+  });
+};
+
+const checkResourceSizes = () => {
+  const entries = performance.getEntriesByType('resource');
+  for (let entry of entries) {
+    checkSizeFields(entry, expectedSize, expectedSize + headerSize);
+  }
+}
+
+const redirectUrl = (redirectSourceOrigin, allowOrigin, targetUrl) => {
+  return redirectSourceOrigin +
+    '/resource-timing/resources/redirect-cors.py?allow_origin=' +
+    encodeURIComponent(allowOrigin) +
+    '&timing_allow_origin=*' +
+    '&location=' + encodeURIComponent(targetUrl);
+}
+
+promise_test(() => {
+  // Use a different URL every time so that the cache behaviour does not
+  // depend on execution order.
+  const directUrl = cacheBustUrl(baseUrl);
+  const sameOriginRedirect = redirectUrl(hostInfo.ORIGIN, '*', directUrl);
+  const crossOriginRedirect = redirectUrl(hostInfo.REMOTE_ORIGIN,
+    hostInfo.ORIGIN, directUrl);
+  const mixedRedirect = redirectUrl(hostInfo.REMOTE_ORIGIN,
+    hostInfo.ORIGIN, sameOriginRedirect);
+  const complexRedirect = redirectUrl(hostInfo.ORIGIN,
+    hostInfo.REMOTE_ORIGIN, mixedRedirect);
+  let eatBody = response => response.arrayBuffer();
+  return fetch(directUrl)
+    .then(eatBody)
+    .then(() => fetch(sameOriginRedirect))
+    .then(eatBody)
+    .then(() => fetch(crossOriginRedirect))
+    .then(eatBody)
+    .then(() => fetch(mixedRedirect))
+    .then(eatBody)
+    .then(() => fetch(complexRedirect))
+    .then(eatBody)
+    .then(accumulateEntry)
+    .then(checkResourceSizes);
+}, 'PerformanceResourceTiming sizes Fetch with redirect test');
+
+done();
diff --git a/third_party/blink/web_tests/external/wpt/url/failure.html b/third_party/blink/web_tests/external/wpt/url/failure.html
index 8f3d0299..c22357b6 100644
--- a/third_party/blink/web_tests/external/wpt/url/failure.html
+++ b/third_party/blink/web_tests/external/wpt/url/failure.html
@@ -28,22 +28,27 @@
       assert_throws_js(TypeError, () => url.href = test.input)
     }, "URL's href: " + name)
 
-    self.test(() => {
-      const client = new XMLHttpRequest()
-      assert_throws_dom("SyntaxError", () => client.open("GET", test.input))
-    }, "XHR: " + name)
+    // The following use cases resolve the URL input relative to the current
+    // document's URL. If this test input could be construed as a valid URL
+    // when resolved against a base URL, skip these cases.
+    if (!test.inputCanBeRelative) {
+      self.test(() => {
+        const client = new XMLHttpRequest()
+        assert_throws_dom("SyntaxError", () => client.open("GET", test.input))
+      }, "XHR: " + name)
 
-    self.test(() => {
-      assert_throws_js(TypeError, () => self.navigator.sendBeacon(test.input))
-    }, "sendBeacon(): " + name)
+      self.test(() => {
+        assert_throws_js(TypeError, () => self.navigator.sendBeacon(test.input))
+      }, "sendBeacon(): " + name)
 
-    self.test(() => {
-      assert_throws_js(self[0].TypeError, () => self[0].location = test.input)
-    }, "Location's href: " + name)
+      self.test(() => {
+        assert_throws_js(self[0].TypeError, () => self[0].location = test.input)
+      }, "Location's href: " + name)
 
-    self.test(() => {
-      assert_throws_dom("SyntaxError", () => self.open(test.input).close())
-    }, "window.open(): " + name)
+      self.test(() => {
+        assert_throws_dom("SyntaxError", () => self.open(test.input).close())
+      }, "window.open(): " + name)
+    }
   }
 }
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json b/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
index 1adea15..96c42d2 100644
--- a/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
+++ b/third_party/blink/web_tests/external/wpt/url/resources/urltestdata.json
@@ -3156,7 +3156,8 @@
   {
     "input": "http:/:@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http://user@/www.example.com",
@@ -3166,12 +3167,14 @@
   {
     "input": "http:@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http:/@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http://@/www.example.com",
@@ -3181,17 +3184,20 @@
   {
     "input": "https:@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http:a:b@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http:/a:b@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http://a:b@/www.example.com",
@@ -3201,7 +3207,8 @@
   {
     "input": "http::@/www.example.com",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "http:a:@www.example.com",
@@ -7331,17 +7338,20 @@
   {
     "input": "a",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "a/",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   {
     "input": "a//",
     "base": "about:blank",
-    "failure": true
+    "failure": true,
+    "inputCanBeRelative": true
   },
   "Bases that don't fail to parse but fail to be bases",
   {
diff --git a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker.js b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker.js
index 8eb41c23..d4f4835 100644
--- a/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker.js
+++ b/third_party/blink/web_tests/external/wpt/workers/semantics/interface-objects/002.worker.js
@@ -19,8 +19,6 @@
   "PageTransitionEvent",
   // https://dom.spec.whatwg.org/
   "DOMImplementation",
-  // https://streams.spec.whatwg.org/
-  "WritableStreamDefaultController",
   // http://w3c.github.io/IndexedDB/
   "IDBEnvironment",
   // https://www.w3.org/TR/2010/NOTE-webdatabase-20101118/
diff --git a/third_party/blink/web_tests/fast/canvas/color-space/canvas-getImageData.html b/third_party/blink/web_tests/fast/canvas/color-space/canvas-getImageData.html
index 2cd1997..c09bd44e 100644
--- a/third_party/blink/web_tests/fast/canvas/color-space/canvas-getImageData.html
+++ b/third_party/blink/web_tests/fast/canvas/color-space/canvas-getImageData.html
@@ -21,7 +21,16 @@
   ctx.fillStyle = color_style;
   ctx.fillRect(0, 0, 10, 10);
 
-  var pixel = ctx.getImageData(5, 5, 1, 1, {colorSpace: data_color_space, storageFormat:data_storage_format}).data;
+  var data;
+  if (data_color_space) {
+    data = ctx.getImageData(5, 5, 1, 1, {colorSpace: data_color_space, storageFormat:data_storage_format});
+  } else {
+    // If no color space is specified, then getImageData should default to the canvas' color space.
+    data = ctx.getImageData(5, 5, 1, 1, {storageFormat:data_storage_format});
+    data_color_space = canvas_color_space;
+  }
+  assert_true(data_color_space === data.colorSpace);
+  var pixel = data.data;
 
   var epsilon = epsilon_f32;
   var pixel_expected;
@@ -63,13 +72,13 @@
 }
 
 function drawThenGetImageData() {
-  color_spaces = ['srgb', 'display-p3', 'rec2020'];
+  color_spaces = ['srgb', 'display-p3', 'rec2020', null];
   canvas_pixel_formats = ['uint8', 'float16'];
   image_data_pixel_formats = ['uint8', 'uint16', 'float32'];
   var passed = true;
   for (var i = 0; i < 3; ++i) {
     for (var j = 0; j < 2; ++j) {
-      for (var k = 0; k < 3; ++k) {
+      for (var k = 0; k < 4; ++k) {
         for (var l = 0; l < 3; ++l) {
           if (!run_test(color_spaces[i],
                         canvas_pixel_formats[j],
diff --git a/third_party/blink/web_tests/fast/canvas/color-space/canvas-putImageData.html b/third_party/blink/web_tests/fast/canvas/color-space/canvas-putImageData.html
index dac5764..d141a7c 100644
--- a/third_party/blink/web_tests/fast/canvas/color-space/canvas-putImageData.html
+++ b/third_party/blink/web_tests/fast/canvas/color-space/canvas-putImageData.html
@@ -119,7 +119,7 @@
 
   // Read back as 8-bit sRGB.
   for (var j = 0; j < num_subtests; ++j) {
-    var data_from_get = ctx.getImageData(data_width * (j + 0.5), data_height / 2, 1, 1);
+    var data_from_get = ctx.getImageData(data_width * (j + 0.5), data_height / 2, 1, 1, {colorSpace:'srgb'});
     var passed = true;
     var pixel_expected = [50, 100, 150, 255];
     var pixel_actual = data_from_get.data;
diff --git a/third_party/blink/web_tests/fast/css/containment/DIR_METADATA b/third_party/blink/web_tests/fast/css/containment/DIR_METADATA
index 549979e..6ff4edb 100644
--- a/third_party/blink/web_tests/fast/css/containment/DIR_METADATA
+++ b/third_party/blink/web_tests/fast/css/containment/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 
diff --git a/third_party/blink/web_tests/fast/css/content/DIR_METADATA b/third_party/blink/web_tests/fast/css/content/DIR_METADATA
index 549979e..6ff4edb 100644
--- a/third_party/blink/web_tests/fast/css/content/DIR_METADATA
+++ b/third_party/blink/web_tests/fast/css/content/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 
diff --git a/third_party/blink/web_tests/fast/css/counters/DIR_METADATA b/third_party/blink/web_tests/fast/css/counters/DIR_METADATA
index 549979e..6ff4edb 100644
--- a/third_party/blink/web_tests/fast/css/counters/DIR_METADATA
+++ b/third_party/blink/web_tests/fast/css/counters/DIR_METADATA
@@ -1,5 +1,4 @@
 monorail {
   component: "Blink>Layout"
 }
-team_email: "layout-dev@chromium.org"
 
diff --git a/third_party/blink/web_tests/fast/css/list-item-height-expected.png b/third_party/blink/web_tests/fast/css/list-item-height-expected.png
new file mode 100644
index 0000000..b69da18
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css/list-item-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/fast/css/list-item-height.html b/third_party/blink/web_tests/fast/css/list-item-height.html
new file mode 100644
index 0000000..b8b2c196
--- /dev/null
+++ b/third_party/blink/web_tests/fast/css/list-item-height.html
@@ -0,0 +1,7 @@
+<!-- quirks mode -->
+<p>List-item lines should not be overwrapped. crbug.com/1134166</p>
+<ul style="width:251px">
+<li><span style="font-size:36px">Sample text sample text Sample text sample text </span></li>
+<li><span style="font-size:14px">Sample text sample text Sample text sample text </span></li>
+</ul>
+
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/list-item-height-expected.png b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/list-item-height-expected.png
new file mode 100644
index 0000000..22eff49
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/fast/css/list-item-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache-worker.html b/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache-worker.html
deleted file mode 100644
index fbd3e91a..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache-worker.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-fetch_tests_from_worker(
-    new Worker('/misc/resources/resource-timing-sizes-cache.js'));
-</script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache.html b/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache.html
deleted file mode 100644
index f55b9b3a..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-cache.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/misc/resources/run-async-tasks-promise.js"></script>
-<script src="/misc/resources/resource-timing-sizes-cache.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-img.html b/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-img.html
deleted file mode 100644
index 7955fe6..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-img.html
+++ /dev/null
@@ -1,104 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js?pipe=sub"></script>
-<script>
-  // Redirects for fetch() always apply CORS rules, whereas normal resources
-  // don't, so this test covers extra code paths beyond those covered by
-  // resource-timing-sizes-redirect.html.
-
-  const baseUrl = new URL('/resources/square20-with-tao.php', location.href).href;
-
-  // Because apache decrements the Keep-Alive max value on each request, the
-  // transferSize will vary slightly between requests for the same resource.
-  const fuzzFactor = 3;  // bytes
-
-  const minHeaderSize = 100;
-
-  const hostInfo = get_host_info();
-
-  var directUrl, sameOriginRedirect, crossOriginRedirect, mixedRedirect;
-  var complexRedirect;
-  var t = async_test('PerformanceResourceTiming sizes redirects img');
-
-  function checkResourceSizes() {
-    var entries = performance.getEntriesByType('resource');
-    var lowerBound, upperBound, withRedirectLowerBound;
-    var seenCount = 0;
-    for (var entry of entries) {
-      switch (entry.name) {
-        case directUrl:
-          assert_greater_than(entry.transferSize, minHeaderSize,
-            'direct transferSize');
-          lowerBound = entry.transferSize - fuzzFactor;
-          upperBound = entry.transferSize + fuzzFactor;
-          withRedirectLowerBound = entry.transferSize + minHeaderSize;
-          ++seenCount;
-          break;
-
-        case sameOriginRedirect:
-          assert_greater_than(entry.transferSize, withRedirectLowerBound,
-            'same origin transferSize');
-          ++seenCount;
-          break;
-
-        case crossOriginRedirect:
-        case mixedRedirect:
-        case complexRedirect:
-          assert_between_exclusive(entry.transferSize, lowerBound, upperBound,
-            'cross origin transferSize');
-          ++seenCount;
-          break;
-
-        default:
-          break;
-      }
-    }
-    assert_equals(seenCount, 5, 'seenCount');
-    t.done();
-  }
-
-  function redirectUrl(redirectSourceOrigin, targetUrl) {
-    return redirectSourceOrigin +
-      '/resources/redirect.php?url=' + encodeURIComponent(targetUrl) + "&timing_allow_origin=*";
-  }
-
-  // Loads the images in |urlArray| in sequence, finally calling |callback|.
-  // |callback| will be wrapped in t.step_func() when called.
-  function loadImages(urlArray, callback) {
-    var url = urlArray.shift();
-    var onload;
-    if (urlArray.length === 0) {
-      onload = t.step_func(callback);
-    } else {
-      onload = () => { loadImages(urlArray, callback); };
-    }
-    var img = document.createElement('img');
-    img.src = url;
-    img.onload = onload;
-    img.onerror = t.step_func(() => assert_unreached('Failed to load ' + url));
-    img.style = 'display: none;';
-  }
-
-  function cacheBustedUrl() {
-    return baseUrl + '?unique=' + Math.random().toString().substring(2);
-  }
-
-  function runTest() {
-    directUrl = cacheBustedUrl();
-    sameOriginRedirect = redirectUrl(hostInfo.HTTP_ORIGIN, cacheBustedUrl());
-    crossOriginRedirect = redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
-      cacheBustedUrl());
-    mixedRedirect = redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
-      redirectUrl(
-        hostInfo.HTTP_ORIGIN, cacheBustedUrl()));
-    complexRedirect = redirectUrl(hostInfo.HTTP_ORIGIN,
-      redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
-        redirectUrl(hostInfo.HTTP_ORIGIN,
-          cacheBustedUrl())));
-    loadImages([directUrl, sameOriginRedirect, crossOriginRedirect,
-      mixedRedirect, complexRedirect], checkResourceSizes);
-  }
-
-  t.step(runTest);
-</script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-worker.html b/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-worker.html
deleted file mode 100644
index 3fbd3919d..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect-worker.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-fetch_tests_from_worker(
-    new Worker('/misc/resources/resource-timing-sizes-redirect.js'));
-</script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect.html b/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect.html
deleted file mode 100644
index b094b4b..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resource-timing-sizes-redirect.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE html>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/get-host-info.js?pipe=sub"></script>
-<script src="/misc/resources/run-async-tasks-promise.js"></script>
-<script src="/misc/resources/resource-timing-sizes-redirect.js"></script>
diff --git a/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-cache.js b/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-cache.js
deleted file mode 100644
index fec5fd0..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-cache.js
+++ /dev/null
@@ -1,66 +0,0 @@
-// This test code is shared between resource-timing-sizes-cache.html and
-// resource-timing-sizes-cache-worker.html
-
-if (typeof document === 'undefined') {
-    importScripts('/resources/testharness.js',
-                  '/misc/resources/run-async-tasks-promise.js');
-}
-
-// The header bytes are expected to be > |minHeaderSize| and
-// < |maxHeaderSize|. If they are outside this range the test will fail.
-const minHeaderSize = 100;
-const maxHeaderSize = 1024;
-
-// The size of this resource must be > maxHeaderSize for the test to be
-// reliable.
-var url = new URL('/resources/square.png', location.href).href;
-const expectedSize = 18299;
-
-function checkBodySizeFields(entry, expectedSize) {
-    assert_equals(entry.decodedBodySize, expectedSize, 'decodedBodySize');
-    assert_equals(entry.encodedBodySize, expectedSize, 'encodedBodySize');
-}
-
-function checkResourceSizes() {
-    var entries = performance.getEntriesByName(url);
-    assert_equals(entries.length, 3, 'Wrong number of entries');
-    var seenCount = 0;
-    for (var entry of entries) {
-        checkBodySizeFields(entry, expectedSize);
-        if (seenCount === 0) {
-            // 200 response
-            assert_between_exclusive(entry.transferSize,
-                                     expectedSize + minHeaderSize,
-                                     expectedSize + maxHeaderSize,
-                                     '200 transferSize');
-        } else if (seenCount === 1) {
-            // from cache
-            assert_equals(entry.transferSize, 0, 'cached transferSize');
-        } else if (seenCount === 2) {
-            // 304 response
-            assert_between_exclusive(entry.transferSize, minHeaderSize,
-                                     maxHeaderSize, '304 transferSize');
-        } else {
-            assert_unreached('Too many matching entries');
-        }
-        ++seenCount;
-    }
-}
-
-promise_test(() => {
-    // Use a different URL every time so that the cache behaviour does not
-    // depend on execution order.
-    url = url + '?unique=' + Math.random().toString().substring(2);
-    var eatBody = response => response.arrayBuffer();
-    var mustRevalidate = {headers: {'Cache-Control': 'max-age=0'}};
-    return fetch(url)
-        .then(eatBody)
-        .then(() => fetch(url))
-        .then(eatBody)
-        .then(() => fetch(url, mustRevalidate))
-        .then(eatBody)
-        .then(runAsyncTasks)
-        .then(checkResourceSizes);
-}, 'PerformanceResourceTiming sizes caching test');
-
-done();
diff --git a/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-redirect.js b/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-redirect.js
deleted file mode 100644
index ef8aba6..0000000
--- a/third_party/blink/web_tests/http/tests/misc/resources/resource-timing-sizes-redirect.js
+++ /dev/null
@@ -1,104 +0,0 @@
-// This test code is shared between resource-timing-sizes-redirect.html and
-// resource-timing-sizes-redirect-worker.html
-
-if (typeof document === 'undefined') {
-  importScripts('/resources/testharness.js',
-    '/resources/get-host-info.js?pipe=sub',
-    '/misc/resources/run-async-tasks-promise.js');
-}
-
-const baseUrl =
-  new URL('/security/resources/cors-hello.php', location.href).href;
-const expectedSize = 73;
-
-// Because apache decrements the Keep-Alive max value on each request, the
-// transferSize will vary slightly between requests for the same resource.
-const fuzzFactor = 3;  // bytes
-
-const minHeaderSize = 100;
-
-const hostInfo = get_host_info();
-
-var directUrl, sameOriginRedirect, crossOriginRedirect, mixedRedirect;
-var complexRedirect;
-
-function checkBodySizeFields(entry) {
-  assert_equals(entry.decodedBodySize, expectedSize, 'decodedBodySize');
-  assert_equals(entry.encodedBodySize, expectedSize, 'encodedBodySize');
-}
-
-function checkResourceSizes() {
-  var entries = performance.getEntriesByType('resource');
-  var lowerBound, upperBound, withRedirectLowerBound;
-  var seenCount = 0;
-  for (var entry of entries) {
-    switch (entry.name) {
-      case directUrl:
-        checkBodySizeFields(entry);
-        assert_greater_than(entry.transferSize, expectedSize,
-          'transferSize');
-        lowerBound = entry.transferSize - fuzzFactor;
-        upperBound = entry.transferSize + fuzzFactor;
-        withRedirectLowerBound = entry.transferSize + minHeaderSize;
-        ++seenCount;
-        break;
-
-      case sameOriginRedirect:
-        checkBodySizeFields(entry);
-        assert_greater_than(entry.transferSize, withRedirectLowerBound,
-          'transferSize');
-        ++seenCount;
-        break;
-
-      case crossOriginRedirect:
-      case mixedRedirect:
-      case complexRedirect:
-        checkBodySizeFields(entry);
-        assert_between_exclusive(entry.transferSize, lowerBound, upperBound,
-          'transferSize');
-        ++seenCount;
-        break;
-
-      default:
-        break;
-    }
-  }
-  assert_equals(seenCount, 5, 'seenCount');
-}
-
-function redirectUrl(redirectSourceOrigin, allowOrigin, targetUrl) {
-  return redirectSourceOrigin +
-    '/resources/redirect.php?cors_allow_origin=' +
-    encodeURIComponent(allowOrigin) +
-    '&url=' + encodeURIComponent(targetUrl) +
-    '&timing_allow_origin=*';
-}
-
-promise_test(() => {
-  // Use a different URL every time so that the cache behaviour does not
-  // depend on execution order.
-  directUrl = baseUrl + '?unique=' + Math.random().toString().substring(2) +
-    '&cors=*';
-  sameOriginRedirect = redirectUrl(hostInfo.HTTP_ORIGIN, '*', directUrl);
-  crossOriginRedirect = redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
-    hostInfo.HTTP_ORIGIN, directUrl);
-  mixedRedirect = redirectUrl(hostInfo.HTTP_REMOTE_ORIGIN,
-    hostInfo.HTTP_ORIGIN, sameOriginRedirect);
-  complexRedirect = redirectUrl(hostInfo.HTTP_ORIGIN,
-    hostInfo.HTTP_REMOTE_ORIGIN, mixedRedirect);
-  var eatBody = response => response.arrayBuffer();
-  return fetch(directUrl)
-    .then(eatBody)
-    .then(() => fetch(sameOriginRedirect))
-    .then(eatBody)
-    .then(() => fetch(crossOriginRedirect))
-    .then(eatBody)
-    .then(() => fetch(mixedRedirect))
-    .then(eatBody)
-    .then(() => fetch(complexRedirect))
-    .then(eatBody)
-    .then(runAsyncTasks)
-    .then(checkResourceSizes);
-}, 'PerformanceResourceTiming sizes Fetch with redirect test');
-
-done();
diff --git a/third_party/blink/web_tests/platform/linux/fast/css/list-item-height-expected.png b/third_party/blink/web_tests/platform/linux/fast/css/list-item-height-expected.png
new file mode 100644
index 0000000..82033c15
--- /dev/null
+++ b/third_party/blink/web_tests/platform/linux/fast/css/list-item-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/linux/svg/text/textpath-connected-glyphs-expected.png
index 9ace4f1..9247d21 100644
--- a/third_party/blink/web_tests/platform/linux/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/linux/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
index def306e6..abb6c1c 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/fast/css/list-item-height-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css/list-item-height-expected.png
new file mode 100644
index 0000000..2ab7e875
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/fast/css/list-item-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/mac/svg/text/textpath-connected-glyphs-expected.png
index 81b6d5a..477f6d4 100644
--- a/third_party/blink/web_tests/platform/mac/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/mac/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
index 00a2483d..f9ddbab8 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/list-item-height-expected.png b/third_party/blink/web_tests/platform/win/fast/css/list-item-height-expected.png
new file mode 100644
index 0000000..5c6d16c4
--- /dev/null
+++ b/third_party/blink/web_tests/platform/win/fast/css/list-item-height-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/win/svg/text/textpath-connected-glyphs-expected.png
index cf4942c..90acac78 100644
--- a/third_party/blink/web_tests/platform/win/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/win/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
index 955edf5..a9a4e04 100644
--- a/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/layout_ng_svg_text/svg/text/textpath-connected-glyphs-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/svg/text/textpath-connected-glyphs.html b/third_party/blink/web_tests/svg/text/textpath-connected-glyphs.html
index 1f350368..792e94e8 100644
--- a/third_party/blink/web_tests/svg/text/textpath-connected-glyphs.html
+++ b/third_party/blink/web_tests/svg/text/textpath-connected-glyphs.html
@@ -1,12 +1,22 @@
 <!DOCTYPE HTML>
 <meta charset="UTF-8">
 
-<p>This test passes if the two lines of text look the same.</p>
+<p>The two lines of text should look same.</p>
 
-<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
+<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200">
   <text x="100" y="100" font-size="28">سلام  ชุตินันท์</text>
-  <path fill="transparent" id="f" d="m100 200 L 300 200Z"/>
+  <path fill="transparent" id="f" d="m100 150 L 300 150Z"/>
   <text font-size="28">
     <textPath xlink:href="#f">سلام  ชุตินันท์</textPath>
   </text>
 </svg>
+
+<p>Connected glyphs on a path should be rotated together.</p>
+
+<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
+  <path id="p2" stroke="blue" fill="transparent" transform="translate(0, 50)"
+               d="M 100 100 C100 -50 200 -50 200 100"/>
+  <text font-size="28" letter-spacing="16">
+    <textPath xlink:href="#p2" startOffset="50">سلام  ชุตินันท์</textPath>
+  </text>
+</svg>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-carry-over-to-prerender-page.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-carry-over-to-prerender-page.html
new file mode 100644
index 0000000..c3a6fe0
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-carry-over-to-prerender-page.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<script src="session-storage-utils.js"></script>
+<script>
+RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
+  if (!isPrerendering) {
+    sessionStorage.setItem('set by initiator page', '1');
+    startPrerendering(url);
+  } else {
+    assert_equals(
+        getSessionStorageKeys(),
+        'set by initiator page',
+        'The session storage item set by the initiator page must be carried' +
+        ' over to the prerendering page.');
+    done();
+  }
+});
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-isolated-while-prerendering.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-isolated-while-prerendering.html
new file mode 100644
index 0000000..4fcd5ac
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-isolated-while-prerendering.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<script src="session-storage-utils.js"></script>
+<script>
+RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
+  if (!isPrerendering) {
+    startPrerendering(url);
+    // Wait for the message from the prerendering page.
+    assert_equals(
+        await getNextMessage(prerenderChannel),
+        'From prerendering page 1')
+
+    // Add an item to the session storage.
+    sessionStorage.setItem('set by initiator page', '1');
+
+    // Send the message to the prerendering page.
+    prerenderChannel.postMessage('From initiator page');
+
+  } else {
+    sessionStorage.setItem('set by prerendering page', '1');
+
+    // Send the message to the initiator page.
+    prerenderChannel.postMessage('From prerendering page 1');
+
+    // Wait for the message from the initiator page.
+    assert_equals(
+        await getNextMessage(prerenderChannel),
+        'From initiator page');
+
+    assert_equals(
+        getSessionStorageKeys(),
+        'set by prerendering page',
+        'The session storage item added by the initiator page after the ' +
+        'prerendering page accessed the session storage must not be visible ' +
+        'in the prerendering page.');
+    done();
+  }
+});
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-no-leak-to-initiator-page.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-no-leak-to-initiator-page.html
new file mode 100644
index 0000000..0348439
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-no-leak-to-initiator-page.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<script src="session-storage-utils.js"></script>
+<script>
+RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
+  if (!isPrerendering) {
+    startPrerendering(url);
+
+    // Wait for the message from the prerendering page.
+    assert_equals(
+        await getNextMessage(prerenderChannel),
+        'From prerendering page')
+
+    assert_equals(
+        getSessionStorageKeys(),
+        '',
+        'The session storage item set by the prerendering page must not be ' +
+        'visible in the initiator page.');
+
+    done();
+  } else {
+    sessionStorage.setItem('set by prerendering page', '1');
+
+    assert_equals(
+        getSessionStorageKeys(),
+        'set by prerendering page',
+        'The session storage item must have been added by the prerendering' +
+        ' page.');
+    // Send the message to the initiator page.
+    prerenderChannel.postMessage('From prerendering page');
+  }
+});
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-swap-after-activate.html b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-swap-after-activate.html
new file mode 100644
index 0000000..f81841b1
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-swap-after-activate.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="utils.js"></script>
+<script src="session-storage-utils.js"></script>
+<script>
+RunSessionStorageTest(async (isPrerendering, url, prerenderChannel, done) => {
+  if (!isPrerendering) {
+    sessionStorage.setItem('set by initiator page 1', '1');
+    startPrerendering(url);
+    // Wait for the message from the prerendering page.
+    assert_equals(
+        await getNextMessage(prerenderChannel),
+        'From prerendering page 1')
+
+    // Add an item to the session storage.
+    sessionStorage.setItem('set by initiator page 2', '1');
+
+    // Send the message to the prerendering page.
+    prerenderChannel.postMessage('From initiator page');
+
+    // Wait for the message from the prerendering page.
+    assert_equals(
+        await getNextMessage(prerenderChannel),
+        'From prerendering page 2')
+
+    // Register beforeunload event handler which adds a new item in the
+    // session storage.
+    window.addEventListener('beforeunload', () => {
+      sessionStorage.setItem('set by initiator page 3', '1');
+    });
+
+    // Navigate to the prerenderered page.
+    window.location = url;
+  } else {
+    const prerenderingchangePromise =
+        new Promise(resolve => {
+            document.addEventListener('prerenderingchange', () => {
+              sessionStorage.setItem('set by activated page', 1);
+              resolve();
+            });
+          });
+
+    sessionStorage.setItem('set by prerendering page', '1');
+
+    // Send the message to the initiator page.
+    prerenderChannel.postMessage('From prerendering page 1');
+
+    // Wait for the message from the initiator page.
+    assert_equals(await getNextMessage(prerenderChannel),
+        'From initiator page');
+
+    assert_equals(
+        getSessionStorageKeys(),
+        'set by initiator page 1, set by prerendering page',
+        'The session storage item added by the initiator page after ' +
+        'starting prerendering must not be visible in the prerendering ' +
+        'page.');
+
+    // Send the message to the initiator page.
+    prerenderChannel.postMessage('From prerendering page 2');
+
+    // Wait until activated.
+    await prerenderingchangePromise;
+
+    assert_equals(
+        getSessionStorageKeys(),
+        'set by activated page, set by initiator page 1, ' +
+        'set by initiator page 2, set by initiator page 3',
+        'The all session storage items added by the initiator page and ' +
+        'the item added by the activated page must be visible in the ' +
+        'activated page.');
+    done();
+  }
+});
+</script>
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-utils.js b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-utils.js
new file mode 100644
index 0000000..d7688607
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/resources/session-storage-utils.js
@@ -0,0 +1,76 @@
+// 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.
+
+function getSessionStorageKeys() {
+  let keys = [];
+  let txt = '';
+  for (let i = 0; i < sessionStorage.length; ++i) {
+    keys.push(sessionStorage.key(i));
+  }
+  keys.sort();
+  keys.forEach((key) => {
+    if (txt.length) {
+      txt += ', ';
+    }
+    txt += key;
+  });
+  return txt;
+}
+
+function getNextMessage(channel) {
+  return new Promise(resolve => {
+    channel.addEventListener('message', e => {
+      resolve(e.data);
+    }, {once: true});
+  });
+}
+
+// session_storage_test() is a utility function for running session storage
+// related tests that open a initiator page using window.open().
+function session_storage_test(testPath) {
+  promise_test(async t => {
+    const testChannel = new BroadcastChannel('test-channel');
+    t.add_cleanup(() => {
+      testChannel.close();
+    });
+    const gotMessage = getNextMessage(testChannel);
+    const url = 'resources/' + testPath;
+    window.open(url, '_blank', 'noopener');
+    assert_equals(await gotMessage, 'Done');
+  }, testPath);
+}
+
+// RunSessionStorageTest() is a utility function for running session storage
+// related tests that requires coordinated code execution on both the initiator
+// page and the prerendering page. The passed |func| function will be called
+// with the following arguments:
+//   - isPrerendering: Whether the |func| is called in the prerendering page.
+//   - url: The URL of the prerendering page. |func| should call
+//     startPrerendering(url) when |isPrerendering| is false to start the
+//     prerendering.
+//   - channel: A Broadcast Channel which can be used to coordinate the code
+//     execution on the initiator page and the prerendering page.
+//   - done: A function that should be called when the test completes
+//     successfully.
+async function RunSessionStorageTest(func) {
+  const url = new URL(document.URL);
+  url.searchParams.set('prerendering', '');
+  const params = new URLSearchParams(location.search);
+  // The main test page loads the initiator page, then the initiator page will
+  // prerender itself with the `prerendering` parameter.
+  const isPrerendering = params.has('prerendering');
+  const prerenderChannel = new BroadcastChannel('prerender-channel');
+  const testChannel = new BroadcastChannel('test-channel');
+  window.addEventListener('unload', () => {
+    prerenderChannel.close();
+    testChannel.close();
+  });
+  try {
+    await func(isPrerendering, url.toString(), prerenderChannel, () => {
+      testChannel.postMessage('Done');
+    })
+  } catch (e) {
+    testChannel.postMessage(e.toString());
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/prerender/session-storage.html b/third_party/blink/web_tests/wpt_internal/prerender/session-storage.html
new file mode 100644
index 0000000..8f6bfc10
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/prerender/session-storage.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!--
+This file cannot be upstreamed to WPT until:
+* startPrerendering() usage is replaced with a WebDriver API.
+* The "clone & swap" mechanism for session storage in prerendering described in
+  https://github.com/whatwg/storage/issues/119 is added to the specification.
+-->
+<title>Same-origin prerendering can access sessionStorage</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/utils.js"></script>
+<script src="resources/session-storage-utils.js"></script>
+<body>
+<script>
+session_storage_test(
+  'session-storage-carry-over-to-prerender-page.html');
+
+session_storage_test(
+  'session-storage-no-leak-to-initiator-page.html');
+
+session_storage_test(
+  'session-storage-isolated-while-prerendering.html');
+
+session_storage_test(
+  'session-storage-swap-after-activate.html');
+</script>
+</body>
diff --git a/third_party/closure_compiler/externs/DIR_METADATA b/third_party/closure_compiler/externs/DIR_METADATA
deleted file mode 100644
index 8325efa..0000000
--- a/third_party/closure_compiler/externs/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail {
-  component: "UI>Browser>WebUI"
-}
diff --git a/third_party/gvr-android-keyboard/com/google/vr/keyboard/DIR_METADATA b/third_party/gvr-android-keyboard/com/google/vr/keyboard/DIR_METADATA
deleted file mode 100644
index ff6e380..0000000
--- a/third_party/gvr-android-keyboard/com/google/vr/keyboard/DIR_METADATA
+++ /dev/null
@@ -1,5 +0,0 @@
-monorail: {
-  component: "UI>Browser>VR"
-}
-team_email: "xr-dev@chromium.org"
-os: ANDROID
diff --git a/third_party/khronos/EGL/DIR_METADATA b/third_party/khronos/EGL/DIR_METADATA
deleted file mode 100644
index 3b153c7..0000000
--- a/third_party/khronos/EGL/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>GPU>Internals"
-}
diff --git a/third_party/khronos/GLES2/DIR_METADATA b/third_party/khronos/GLES2/DIR_METADATA
deleted file mode 100644
index 3b153c7..0000000
--- a/third_party/khronos/GLES2/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>GPU>Internals"
-}
diff --git a/third_party/khronos/GLES3/DIR_METADATA b/third_party/khronos/GLES3/DIR_METADATA
deleted file mode 100644
index 3b153c7..0000000
--- a/third_party/khronos/GLES3/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>GPU>Internals"
-}
diff --git a/third_party/khronos/KHR/DIR_METADATA b/third_party/khronos/KHR/DIR_METADATA
deleted file mode 100644
index 3b153c7..0000000
--- a/third_party/khronos/KHR/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>GPU>Internals"
-}
diff --git a/third_party/khronos/noninclude/DIR_METADATA b/third_party/khronos/noninclude/DIR_METADATA
deleted file mode 100644
index 3b153c7..0000000
--- a/third_party/khronos/noninclude/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>GPU>Internals"
-}
diff --git a/third_party/leveldatabase/leveldb_chrome.cc b/third_party/leveldatabase/leveldb_chrome.cc
index c381de0..a5c2071 100644
--- a/third_party/leveldatabase/leveldb_chrome.cc
+++ b/third_party/leveldatabase/leveldb_chrome.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/containers/contains.h"
 #include "base/containers/flat_set.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
diff --git a/third_party/material_web_components/build_mwc_app.py b/third_party/material_web_components/build_mwc_app.py
index 2d5a8689..6141110 100755
--- a/third_party/material_web_components/build_mwc_app.py
+++ b/third_party/material_web_components/build_mwc_app.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 # Copyright 2021 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -284,12 +284,13 @@
 
     # Output a manifest file that will be used to auto-generate a grd file later.
     if args.out_manifest:
-        manifest_data = {}
-        manifest_data['base_dir'] = '%s' % args.out_folder
-        manifest_data['files'] = manifest.keys()
-        manifest_file = open(
-            os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'wb')
-        json.dump(manifest_data, manifest_file)
+        manifest_data = {
+            'base_dir': args.out_folder,
+            'files': list(manifest.keys()),
+        }
+        with open(os.path.normpath(os.path.join(_CWD, args.out_manifest)), 'w') \
+                as manifest_file:
+            json.dump(manifest_data, manifest_file)
 
     _update_dep_file(args.input, args, manifest)
 
diff --git a/third_party/node/node.gni b/third_party/node/node.gni
index fc2bc48..81c4f2c 100644
--- a/third_party/node/node.gni
+++ b/third_party/node/node.gni
@@ -2,11 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/python.gni")
-
 template("node") {
-  # TODO(crbug.com/1112471): Get this to run cleanly under Python 3.
-  python2_action(target_name) {
+  action(target_name) {
     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
     forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
 
diff --git a/third_party/node/node.py b/third_party/node/node.py
index 09662c4..573987b 100755
--- a/third_party/node/node.py
+++ b/third_party/node/node.py
@@ -27,7 +27,8 @@
 def RunNode(cmd_parts, stdout=None):
   cmd = [GetBinaryPath()] + cmd_parts
   process = subprocess.Popen(
-      cmd, cwd=os.getcwd(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+      cmd, cwd=os.getcwd(), stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+      universal_newlines=True)
   stdout, stderr = process.communicate()
 
   if process.returncode != 0:
diff --git a/third_party/webdriver/OWNERS b/third_party/webdriver/OWNERS
index 0fb7bec5..bd13e16a 100644
--- a/third_party/webdriver/OWNERS
+++ b/third_party/webdriver/OWNERS
@@ -1,7 +1 @@
-# primary reviewer
-mathias@chromium.org
-sadym@chromium.org
-
-# secondary reviewer
-johnchen@chromium.org
-shengfa@google.com
\ No newline at end of file
+file://chrome/test/chromedriver/OWNERS
diff --git a/third_party/zlib/google/zip.cc b/third_party/zlib/google/zip.cc
index c71c738..20cdd57 100644
--- a/third_party/zlib/google/zip.cc
+++ b/third_party/zlib/google/zip.cc
@@ -50,12 +50,12 @@
 
 class DirectFileAccessor : public FileAccessor {
  public:
-  explicit DirectFileAccessor(base::FilePath src_dir) : src_dir_(src_dir) {}
   ~DirectFileAccessor() override = default;
 
   std::vector<base::File> OpenFilesForReading(
       const std::vector<base::FilePath>& paths) override {
     std::vector<base::File> files;
+
     for (const auto& path : paths) {
       base::File file;
       if (base::PathExists(path) && !base::DirectoryExists(path)) {
@@ -63,6 +63,7 @@
       }
       files.push_back(std::move(file));
     }
+
     return files;
   }
 
@@ -73,29 +74,26 @@
   std::vector<DirectoryContentEntry> ListDirectoryContent(
       const base::FilePath& dir) override {
     std::vector<DirectoryContentEntry> files;
+
     base::FileEnumerator file_enumerator(
         dir, false /* recursive */,
         base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
-    for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
+    for (base::FilePath path = file_enumerator.Next(); !path.empty();
          path = file_enumerator.Next()) {
-      files.push_back(DirectoryContentEntry(path, base::DirectoryExists(path)));
+      const bool is_directory = base::DirectoryExists(path);
+      files.push_back({std::move(path), is_directory});
     }
+
     return files;
   }
 
   base::Time GetLastModifiedTime(const base::FilePath& path) override {
     base::File::Info file_info;
     if (!base::GetFileInfo(path, &file_info)) {
-      LOG(ERROR) << "Failed to retrieve file modification time for "
-                 << path.value();
+      LOG(ERROR) << "Cannot get modification time for '" << path << "'";
     }
     return file_info.last_modified;
   }
-
- private:
-  base::FilePath src_dir_;
-
-  DISALLOW_COPY_AND_ASSIGN(DirectFileAccessor);
 };
 
 }  // namespace
@@ -106,7 +104,7 @@
 }
 
 bool Zip(const ZipParams& params) {
-  DirectFileAccessor default_accessor(params.src_dir);
+  DirectFileAccessor default_accessor;
   FileAccessor* const file_accessor = params.file_accessor ?: &default_accessor;
 
   Paths files_to_add = params.src_files;
diff --git a/third_party/zlib/google/zip.h b/third_party/zlib/google/zip.h
index 2c2ef7ae8..ecd7ba0 100644
--- a/third_party/zlib/google/zip.h
+++ b/third_party/zlib/google/zip.h
@@ -35,8 +35,6 @@
   virtual ~FileAccessor() = default;
 
   struct DirectoryContentEntry {
-    DirectoryContentEntry(const base::FilePath& path, bool is_directory)
-        : path(path), is_directory(is_directory) {}
     base::FilePath path;
     bool is_directory = false;
   };
diff --git a/third_party/zlib/google/zip_unittest.cc b/third_party/zlib/google/zip_unittest.cc
index 5a82795..cf914d9 100644
--- a/third_party/zlib/google/zip_unittest.cc
+++ b/third_party/zlib/google/zip_unittest.cc
@@ -79,13 +79,10 @@
     DCHECK(success);
     files_[bar2_txt_path] = std::move(file);
 
-    file_tree_[test_dir] = std::vector<DirectoryContentEntry>{
-        DirectoryContentEntry(foo_txt_path, /*is_dir=*/false),
-        DirectoryContentEntry(bar_dir, /*is_dir=*/true)};
-    file_tree_[bar_dir] = std::vector<DirectoryContentEntry>{
-        DirectoryContentEntry(bar1_txt_path, /*is_dir=*/false),
-        DirectoryContentEntry(bar2_txt_path, /*is_dir=*/false)};
+    file_tree_[test_dir] = {{foo_txt_path, false}, {bar_dir, true}};
+    file_tree_[bar_dir] = {{bar1_txt_path, false}, {bar2_txt_path, false}};
   }
+
   ~VirtualFileSystem() override = default;
 
  private:
@@ -109,7 +106,7 @@
     auto iter = file_tree_.find(dir);
     if (iter == file_tree_.end()) {
       NOTREACHED();
-      return std::vector<DirectoryContentEntry>();
+      return {};
     }
     return iter->second;
   }
diff --git a/tools/android/dependency_analysis/js/DIR_METADATA b/tools/android/dependency_analysis/js/DIR_METADATA
deleted file mode 100644
index a4cad50..0000000
--- a/tools/android/dependency_analysis/js/DIR_METADATA
+++ /dev/null
@@ -1,13 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Infra>CodeAnalysis"
-}
-team_email: "clank-modularization@chromium.org"
-os: ANDROID
\ No newline at end of file
diff --git a/tools/clang/rewrite_to_chrome_style/DIR_METADATA b/tools/clang/rewrite_to_chrome_style/DIR_METADATA
deleted file mode 100644
index fceb01b1..0000000
--- a/tools/clang/rewrite_to_chrome_style/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Tools"
-}
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/fuzzer/DIR_METADATA b/tools/ipc_fuzzer/fuzzer/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/fuzzer/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/message_dump/DIR_METADATA b/tools/ipc_fuzzer/message_dump/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/message_dump/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/message_lib/DIR_METADATA b/tools/ipc_fuzzer/message_lib/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/message_lib/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/message_replay/DIR_METADATA b/tools/ipc_fuzzer/message_replay/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/message_replay/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/message_tools/DIR_METADATA b/tools/ipc_fuzzer/message_tools/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/message_tools/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/ipc_fuzzer/scripts/DIR_METADATA b/tools/ipc_fuzzer/scripts/DIR_METADATA
deleted file mode 100644
index be62a515..0000000
--- a/tools/ipc_fuzzer/scripts/DIR_METADATA
+++ /dev/null
@@ -1,9 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-team_email: "chrome-security-bugs--@chromium.org"
\ No newline at end of file
diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py
index 6708dff..7f453e8f 100644
--- a/tools/json_schema_compiler/cc_generator.py
+++ b/tools/json_schema_compiler/cc_generator.py
@@ -807,7 +807,9 @@
         var = '*%s' % var
       return 'std::make_unique<base::Value>(%s)' % var
     elif underlying_type.property_type == PropertyType.ARRAY:
-      return '%s' % self._util_cc_helper.CreateValueFromArray(var, is_ptr)
+      if is_ptr:
+        var = '*%s' % var
+      return '%s' % self._util_cc_helper.CreateValueFromArray(var)
     elif (underlying_type.property_type.is_fundamental or
               underlying_type.is_serializable_function):
       if is_ptr:
diff --git a/tools/json_schema_compiler/test/test_util.cc b/tools/json_schema_compiler/test/test_util.cc
index e377f5d..61076b5 100644
--- a/tools/json_schema_compiler/test/test_util.cc
+++ b/tools/json_schema_compiler/test/test_util.cc
@@ -48,7 +48,7 @@
     const std::string& ak,
     std::unique_ptr<base::Value> av) {
   auto dict = std::make_unique<base::DictionaryValue>();
-  dict->SetWithoutPathExpansion(ak, std::move(av));
+  dict->SetKey(ak, base::Value::FromUniquePtrValue(std::move(av)));
   return dict;
 }
 std::unique_ptr<base::DictionaryValue> Dictionary(
@@ -57,8 +57,8 @@
     const std::string& bk,
     std::unique_ptr<base::Value> bv) {
   auto dict = std::make_unique<base::DictionaryValue>();
-  dict->SetWithoutPathExpansion(ak, std::move(av));
-  dict->SetWithoutPathExpansion(bk, std::move(bv));
+  dict->SetKey(ak, base::Value::FromUniquePtrValue(std::move(av)));
+  dict->SetKey(bk, base::Value::FromUniquePtrValue(std::move(bv)));
   return dict;
 }
 std::unique_ptr<base::DictionaryValue> Dictionary(
@@ -69,9 +69,9 @@
     const std::string& ck,
     std::unique_ptr<base::Value> cv) {
   auto dict = std::make_unique<base::DictionaryValue>();
-  dict->SetWithoutPathExpansion(ak, std::move(av));
-  dict->SetWithoutPathExpansion(bk, std::move(bv));
-  dict->SetWithoutPathExpansion(ck, std::move(cv));
+  dict->SetKey(ak, base::Value::FromUniquePtrValue(std::move(av)));
+  dict->SetKey(bk, base::Value::FromUniquePtrValue(std::move(bv)));
+  dict->SetKey(ck, base::Value::FromUniquePtrValue(std::move(cv)));
   return dict;
 }
 
diff --git a/tools/json_schema_compiler/util.h b/tools/json_schema_compiler/util.h
index 9e404d82..865ed178 100644
--- a/tools/json_schema_compiler/util.h
+++ b/tools/json_schema_compiler/util.h
@@ -182,12 +182,6 @@
   return std::move(list);
 }
 
-template <class T>
-std::unique_ptr<base::Value> CreateValueFromOptionalArray(
-    const std::unique_ptr<std::vector<T>>& from) {
-  return from ? CreateValueFromArray(*from) : nullptr;
-}
-
 }  // namespace util
 }  // namespace json_schema_compiler
 
diff --git a/tools/json_schema_compiler/util_cc_helper.py b/tools/json_schema_compiler/util_cc_helper.py
index bae1b73..40fb30e 100644
--- a/tools/json_schema_compiler/util_cc_helper.py
+++ b/tools/json_schema_compiler/util_cc_helper.py
@@ -19,18 +19,12 @@
                             else 'PopulateArrayFromList')
     return ('%s::%s') % (_API_UTIL_NAMESPACE, populate_list_fn)
 
-  def CreateValueFromArray(self, src, optional):
+  def CreateValueFromArray(self, src):
     """Generates code to create a scoped_pt<Value> from the array at src.
 
     |src| The variable to convert, either a vector or std::unique_ptr<vector>.
-    |optional| Whether |type_| was optional. Optional types are pointers so
-        must be treated differently.
     """
-    if optional:
-      name = 'CreateValueFromOptionalArray'
-    else:
-      name = 'CreateValueFromArray'
-    return '%s::%s(%s)' % (_API_UTIL_NAMESPACE, name, src)
+    return '%s::CreateValueFromArray(%s)' % (_API_UTIL_NAMESPACE, src)
 
   def GetIncludePath(self):
     return '#include "tools/json_schema_compiler/util.h"'
diff --git a/tools/metrics/histograms/DIR_METADATA b/tools/metrics/histograms/DIR_METADATA
deleted file mode 100644
index 35d6bbc8..0000000
--- a/tools/metrics/histograms/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Metrics"
-}
\ No newline at end of file
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ed7b446..87bfa43 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -5138,6 +5138,10 @@
   <int value="2" label="CART_RETURNING_USER"/>
   <int value="3" label="CHECKOUT_FIRST_TIME_USER"/>
   <int value="4" label="CHECKOUT_RETURNING_TIME_USER"/>
+  <int value="5" label="IN_CHROME_CART_FIRST_TIME_USER"/>
+  <int value="6" label="IN_CHROME_CART_RETURNING_USER"/>
+  <int value="7" label="IN_CHROME_CHECKOUT_FIRST_TIME_USER"/>
+  <int value="8" label="IN_CHROME_CHECKOUT_RETURNING_USER"/>
 </enum>
 
 <enum name="AutofillAwGSuggestionAvailability">
@@ -32510,6 +32514,9 @@
   <int value="3909" label="RTCOfferAnswerOptionsVoiceActivityDetection"/>
   <int value="3910" label="MultiColAndListItem"/>
   <int value="3911" label="CaptureHandle"/>
+  <int value="3912" label="SVGText"/>
+  <int value="3913" label="GetBBoxForText"/>
+  <int value="3914" label="SVGTextHangingFromPath"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -39182,6 +39189,22 @@
              matched the static list."/>
 </enum>
 
+<enum name="HTMLMediaElement_ProgressEventTimerState">
+  <int value="0" label="networkState is not NETWORK_LOADING."/>
+  <int value="1" label="MediaShouldBeOpaque() is true."/>
+  <int value="2" label="progress event was scheduled."/>
+  <int value="3" label="No progress. The stalled event was scheduled."/>
+  <int value="4"
+      label="No progress. No stalled event scheduled because a Media Source
+             Attachment is used."/>
+  <int value="5"
+      label="No progress. No stalled event scheduled because there was recent
+             progress."/>
+  <int value="6"
+      label="No progress. No stalled event scheduled because it was already
+             scheduled."/>
+</enum>
+
 <enum name="HttpAuthCount">
   <int value="0" label="Basic Start"/>
   <int value="1" label="Basic Reject"/>
diff --git a/tools/metrics/histograms/histograms_xml/auto/histograms.xml b/tools/metrics/histograms/histograms_xml/auto/histograms.xml
index 73667a82..7be0a65 100644
--- a/tools/metrics/histograms/histograms_xml/auto/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/auto/histograms.xml
@@ -22,7 +22,7 @@
 <histograms>
 
 <histogram name="AutoScreenBrightness.AdapterDecisionAtUserChange.AlsDelta"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
 <!-- Name completed by histogram_suffixes name="AlsBrightnessDirection" and name="AdapterDecision" -->
 
   <owner>wrong@chromium.org</owner>
@@ -38,7 +38,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.AdapterDecisionAtUserChange.AlsStd"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
 <!-- Name completed by histogram_suffixes name="AlsBrightnessDirection" and name="AdapterDecision" -->
 
   <owner>wrong@chromium.org</owner>
@@ -54,7 +54,7 @@
 
 <histogram
     name="AutoScreenBrightness.AdapterDecisionAtUserChange.BrightnessChange.Cause"
-    enum="AutoScreenBrightnessBrightnessChangeCause" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessBrightnessChangeCause" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -67,7 +67,7 @@
 
 <histogram base="true"
     name="AutoScreenBrightness.AdapterDecisionAtUserChange.ModelIteration"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
 <!-- Name completed by histogram_suffixes name="AdapterDecision" -->
 
   <owner>wrong@chromium.org</owner>
@@ -83,7 +83,7 @@
 <histogram
     name="AutoScreenBrightness.AdapterDecisionAtUserChange.NoBrightnessChange.Cause"
     enum="AutoScreenBrightnessNoBrightnessChangeCause"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -96,7 +96,7 @@
 
 <histogram
     name="AutoScreenBrightness.AdapterDecisionAtUserChange.Unknown.AlsStd"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
 <!-- Name completed by histogram_suffixes name="AdapterDecision" -->
 
   <owner>wrong@chromium.org</owner>
@@ -111,7 +111,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.AlsReaderStatus"
-    enum="AutoScreenBrightnessAlsReaderStatus" expires_after="2021-08-29">
+    enum="AutoScreenBrightnessAlsReaderStatus" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -121,7 +121,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.BrightnessChange.Cause"
-    enum="AutoScreenBrightnessBrightnessChangeCause" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessBrightnessChangeCause" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -129,7 +129,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.BrightnessChange.ElapsedTime" units="ms"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -139,7 +139,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.BrightnessChange.ModelIteration"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -151,7 +151,7 @@
 
 <histogram name="AutoScreenBrightness.BrightnessMonitorStatus"
     enum="AutoScreenBrightnessBrightnessMonitorStatus"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -162,7 +162,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.Atlas" units="count"
-    expires_after="2021-10-31">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -179,7 +179,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.Eve" units="count"
-    expires_after="2021-08-29">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -195,7 +195,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.Kohaku" units="count"
-    expires_after="2021-10-31">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -212,7 +212,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.NoAls" units="count"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -228,7 +228,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.Nocturne"
-    units="count" expires_after="2021-10-31">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -245,7 +245,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.SupportedAls"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -261,7 +261,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DailyUserAdjustment.UnsupportedAls"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -277,7 +277,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.DataError"
-    enum="AutoScreenBrightnessDataError" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessDataError" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -289,7 +289,7 @@
 
 <histogram
     name="AutoScreenBrightness.ElapsedTimeBetweenModelAndUserAdjustments"
-    units="ms" expires_after="2021-06-30">
+    units="ms" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -300,7 +300,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.GlobalCurveResetOnInitialization"
-    enum="Boolean" expires_after="2021-10-31">
+    enum="Boolean" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -308,7 +308,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.InvalidCurveReason"
-    enum="AutoScreenBrightnessInvalidCurveReason" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessInvalidCurveReason" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -319,7 +319,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.MissingAlsWhenBrightnessChanged"
-    enum="BooleanError" expires_after="2021-06-30">
+    enum="BooleanError" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -329,7 +329,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.MissingPriorUserBrightnessRequest"
-    enum="BooleanError" expires_after="2021-06-30">
+    enum="BooleanError" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -343,7 +343,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelIterationCountAtInitialization"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>napper@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
@@ -354,7 +354,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelLoadingStatus"
-    enum="AutoScreenBrightnessModelLoadingStatus" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessModelLoadingStatus" expires_after="2022-04-30">
   <owner>napper@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
@@ -364,7 +364,7 @@
 
 <histogram name="AutoScreenBrightness.ModelTraining.BrightnessChange"
     enum="AutoScreenBrightnessBoundedBrightnessChange"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -375,7 +375,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelTraining.BrightnessOutlier"
-    enum="Boolean" expires_after="2021-06-30">
+    enum="Boolean" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -386,7 +386,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelTraining.Inaccuracy.NoUpdate"
-    units="%" expires_after="2021-06-30">
+    units="%" expires_after="2022-04-30">
   <owner>napper@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
@@ -399,7 +399,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelTraining.Inaccuracy.Update"
-    units="%" expires_after="2021-06-30">
+    units="%" expires_after="2022-04-30">
   <owner>napper@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
@@ -412,7 +412,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ModelTraining.ModelUserConsistent"
-    enum="Boolean" expires_after="2021-06-30">
+    enum="Boolean" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -423,7 +423,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.NewCurveSaved.Duration" units="ms"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -435,7 +435,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.NewCurveSaved.Success"
-    enum="BooleanSuccess" expires_after="2021-06-30">
+    enum="BooleanSuccess" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -446,7 +446,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.Opposite.UserModelBrightnessAdjustments"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -459,7 +459,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.ParameterError"
-    enum="AutoScreenBrightnessParameterError" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessParameterError" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -470,7 +470,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.PersonalCurveValid" enum="BooleanValid"
-    expires_after="2021-06-30">
+    expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -480,7 +480,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.Same.UserModelBrightnessAdjustments"
-    units="count" expires_after="2021-06-30">
+    units="count" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -493,7 +493,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.TrainingCompleteDuration.NewCurve"
-    units="ms" expires_after="2021-06-30">
+    units="ms" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -504,7 +504,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.TrainingCompleteDuration.NoNewCurve"
-    units="ms" expires_after="2021-06-30">
+    units="ms" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
@@ -515,7 +515,7 @@
 </histogram>
 
 <histogram name="AutoScreenBrightness.UserAdjustmentEffect"
-    enum="AutoScreenBrightnessUserAdjustmentEffect" expires_after="2021-06-30">
+    enum="AutoScreenBrightnessUserAdjustmentEffect" expires_after="2022-04-30">
   <owner>wrong@chromium.org</owner>
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index d973b55..8c07aae7 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -41,7 +41,7 @@
 </variants>
 
 <histogram name="ChromeOS.Apps.ExternalProtocolDialog"
-    enum="ArcIntentHandlerAction" expires_after="2021-10-25">
+    enum="ArcIntentHandlerAction" expires_after="M94">
   <owner>dominickn@chromium.org</owner>
   <owner>melzhang@chromium.org</owner>
   <owner>mxcai@chromium.org</owner>
@@ -52,7 +52,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Apps.ExternalProtocolDialog.Accepted"
-    enum="ArcExternalProtocolAction" expires_after="2021-08-22">
+    enum="ArcExternalProtocolAction" expires_after="M94">
   <owner>dominickn@chromium.org</owner>
   <owner>melzhang@chromium.org</owner>
   <owner>mxcai@chromium.org</owner>
@@ -64,7 +64,7 @@
 </histogram>
 
 <histogram name="ChromeOS.Apps.ExternalProtocolDialog.Rejected"
-    enum="ArcExternalProtocolAction" expires_after="M90">
+    enum="ArcExternalProtocolAction" expires_after="M94">
   <owner>dominickn@chromium.org</owner>
   <owner>melzhang@chromium.org</owner>
   <owner>mxcai@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/event/histograms.xml b/tools/metrics/histograms/histograms_xml/event/histograms.xml
index e389751..97212feb 100644
--- a/tools/metrics/histograms/histograms_xml/event/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/event/histograms.xml
@@ -1024,6 +1024,27 @@
   </summary>
 </histogram>
 
+<histogram name="Event.Latency.ScrollUpdate.JankyDuration" units="ms"
+    expires_after="2022-05-20">
+  <owner>ddrone@google.com</owner>
+  <owner>chrometto-team@google.com</owner>
+  <summary>
+    Total duration (wall time in milliseconds of potentially concurrent events)
+    of LatencyInfo::GestureScrollUpdate events that are detected as janky during
+    a particular scroll.
+  </summary>
+</histogram>
+
+<histogram name="Event.Latency.ScrollUpdate.JankyEvents" units="counts"
+    expires_after="2022-05-20">
+  <owner>ddrone@google.com</owner>
+  <owner>chrometto-team@google.com</owner>
+  <summary>
+    Count of LatencyInfo::GestureScrollUpdate events that are detected as janky
+    during a particular scroll.
+  </summary>
+</histogram>
+
 <histogram
     name="Event.Latency.ScrollUpdate.Scrollbar.BrowserNotifiedToBeforeGpuSwap2"
     units="microseconds" expires_after="2021-12-01">
@@ -1168,6 +1189,25 @@
   </summary>
 </histogram>
 
+<histogram name="Event.Latency.ScrollUpdate.TotalDuration" units="ms"
+    expires_after="2022-05-20">
+  <owner>ddrone@google.com</owner>
+  <owner>chrometto-team@google.com</owner>
+  <summary>
+    Total duration (wall time in milliseconds of potentially concurrent events)
+    of LatencyInfo::GestureScrollUpdate events during a particular scroll.
+  </summary>
+</histogram>
+
+<histogram name="Event.Latency.ScrollUpdate.TotalEvents" units="counts"
+    expires_after="2022-05-20">
+  <owner>ddrone@google.com</owner>
+  <owner>chrometto-team@google.com</owner>
+  <summary>
+    Count of LatencyInfo::GestureScrollUpdate events during a particular scroll.
+  </summary>
+</histogram>
+
 <histogram name="Event.Latency.ScrollUpdate.Touch.AverageLag" units="pixels"
     expires_after="M97">
   <owner>flackr@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/local/histograms.xml b/tools/metrics/histograms/histograms_xml/local/histograms.xml
index e227dfe..cb8914c 100644
--- a/tools/metrics/histograms/histograms_xml/local/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/local/histograms.xml
@@ -61,7 +61,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.Backend" enum="LocalSearchServiceBackend"
-    expires_after="2021-06-30">
+    expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
@@ -98,7 +98,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.DailySearch" units="count"
-    expires_after="2021-06-30">
+    expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
@@ -128,7 +128,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.MetricsDailyEventInterval"
-    enum="DailyEventIntervalType" expires_after="2021-06-30">
+    enum="DailyEventIntervalType" expires_after="2021-12-30">
   <owner>tby@chromium.org</owner>
   <owner>thanhdng@chromium.org</owner>
   <owner>wrong@chromium.org</owner>
@@ -138,7 +138,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.NumberDocuments" units="count"
-    expires_after="2021-06-30">
+    expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
@@ -152,7 +152,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.NumberResults" units="count"
-    expires_after="2021-06-30">
+    expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
@@ -177,7 +177,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.ResponseStatus"
-    enum="LocalSearchServiceResponseStatus" expires_after="2021-06-30">
+    enum="LocalSearchServiceResponseStatus" expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
@@ -189,7 +189,7 @@
 </histogram>
 
 <histogram name="LocalSearchService.SearchLatency" units="ms"
-    expires_after="2021-06-30">
+    expires_after="2021-12-30">
 <!-- Name completed by histogram_suffixes name="IndexId" -->
 
   <owner>tby@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/media/histograms.xml b/tools/metrics/histograms/histograms_xml/media/histograms.xml
index 51f642ec..5aa40f7 100644
--- a/tools/metrics/histograms/histograms_xml/media/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/media/histograms.xml
@@ -3229,6 +3229,18 @@
   </summary>
 </histogram>
 
+<histogram name="Media.ProgressEventTimerState"
+    enum="HTMLMediaElement_ProgressEventTimerState" expires_after="2021-08-01">
+  <owner>fdoray@chromium.org</owner>
+  <owner>media-dev@chromium.org</owner>
+  <summary>
+    Records the state of an HTMLMediaElement when its &quot;progress event&quot;
+    timer fires. Used to determine how often the timer causes unnecessary wake
+    ups, to prioritize crbug.com/1143317 and measure the impact of eventual
+    fixes.
+  </summary>
+</histogram>
+
 <histogram name="Media.RebuffersCount" units="rebuffers" expires_after="never">
 <!-- expires-never: Media pipeline health metric. -->
 
@@ -3546,7 +3558,7 @@
 </histogram>
 
 <histogram name="Media.RTCVideoDecoderFirstFrameLatencyMs" units="ms"
-    expires_after="2021-05-02">
+    expires_after="2021-06-02">
   <owner>liberato@chromium.org</owner>
   <owner>webrtc-video@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
index 7a3cb99..c3b6eb9a 100644
--- a/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/navigation/histograms.xml
@@ -157,6 +157,20 @@
   </summary>
 </histogram>
 
+<histogram name="BackForwardCache.CountEntriesWithoutRendererAck" units="count"
+    expires_after="2021-10-01">
+  <owner>yuzus@chromium.org</owner>
+  <owner>bfcache-dev@chromium.org</owner>
+  <summary>
+    This metric is emitted when we try to enforce the cache size limit, which is
+    1) when a page enters BackForwardCache and 2) when a page entering
+    BackForwardCache receives an acknowledgement from the renderer.
+
+    This reports the number of the entries that have not received an
+    acknowledgement from the renderer.
+  </summary>
+</histogram>
+
 <histogram name="BackForwardCache.EvictedAfterDocumentRestoredReason"
     enum="BackForwardCacheEvictedAfterDocumentRestoredReason"
     expires_after="2021-10-17">
diff --git a/tools/metrics/histograms/histograms_xml/net/DIR_METADATA b/tools/metrics/histograms/histograms_xml/net/DIR_METADATA
deleted file mode 100644
index 35d6bbc8..0000000
--- a/tools/metrics/histograms/histograms_xml/net/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Metrics"
-}
\ No newline at end of file
diff --git a/tools/metrics/histograms/histograms_xml/net/histograms.xml b/tools/metrics/histograms/histograms_xml/net/histograms.xml
index 341839b..321823d 100644
--- a/tools/metrics/histograms/histograms_xml/net/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/net/histograms.xml
@@ -414,7 +414,7 @@
 </histogram>
 
 <histogram name="Net.Cors.AccessCheckError" enum="CorsAccessCheckError"
-    expires_after="M90">
+    expires_after="M98">
   <owner>toyoshim@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
@@ -446,7 +446,7 @@
 </histogram>
 
 <histogram name="Net.Cors.PreflightCacheKeySize" units="bytes"
-    expires_after="M90">
+    expires_after="M98">
   <owner>toyoshim@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
@@ -456,7 +456,7 @@
 </histogram>
 
 <histogram name="Net.Cors.PreflightCacheResult" enum="CorsPreflightCacheResult"
-    expires_after="M90">
+    expires_after="M98">
   <owner>toyoshim@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
@@ -466,7 +466,7 @@
 </histogram>
 
 <histogram name="Net.Cors.PreflightCheckError" enum="CorsAccessCheckError"
-    expires_after="M90">
+    expires_after="M98">
   <owner>toyoshim@chromium.org</owner>
   <owner>yhirano@chromium.org</owner>
   <summary>
diff --git a/tools/nocompile_driver.py b/tools/nocompile_driver.py
index 8f983259..df14cbbf9 100755
--- a/tools/nocompile_driver.py
+++ b/tools/nocompile_driver.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
 # Copyright (c) 2011 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.
@@ -15,8 +15,8 @@
 
 from __future__ import print_function
 
-import StringIO
 import ast
+import io
 import os
 import re
 import select
@@ -225,8 +225,8 @@
     cmdline.append('-D%s' % name)
   cmdline.extend(['-o', '/dev/null', '-c', '-x', 'c++',
                   sourcefile_path])
-  test_stdout = tempfile.TemporaryFile(dir=tempfile_dir)
-  test_stderr = tempfile.TemporaryFile(dir=tempfile_dir)
+  test_stdout = tempfile.TemporaryFile(dir=tempfile_dir, mode='w+')
+  test_stderr = tempfile.TemporaryFile(dir=tempfile_dir, mode='w+')
 
   process = subprocess.Popen(cmdline, stdout=test_stdout, stderr=test_stderr)
   now = time.time()
@@ -448,8 +448,8 @@
   test_configs = ExtractTestConfigs(sourcefile_path, suite_name)
   timings['extract_done'] = time.time()
 
-  resultfile = StringIO.StringIO()
-  resultlog = StringIO.StringIO()
+  resultfile = io.StringIO()
+  resultlog = io.StringIO()
   resultfile.write(RESULT_FILE_HEADER % sourcefile_path)
 
   # Run the no-compile tests, but ensure we do not run more than |parallelism|
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index a828be97..0b9ed6e 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -5,12 +5,12 @@
             "remote_path": "perfetto_binaries/trace_processor_shell/win/5e76bff1ab36ae7b07baa0ee2cad749954312590/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "a46eed3a514ac383ab1120c55a2bf90dcd3ba99b",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/5e76bff1ab36ae7b07baa0ee2cad749954312590/trace_processor_shell"
+            "hash": "3739b206be05974814710b0d89234088dafad257",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/b91884a97a74eee3d9dde816a107e934550ccf26/trace_processor_shell"
         },
         "linux": {
-            "hash": "7c885e2fe6c6803c01bfa03fa68b5af7da0a3f01",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/5e76bff1ab36ae7b07baa0ee2cad749954312590/trace_processor_shell"
+            "hash": "49882ef6447cc9a26ae7226e86416be1bce74b30",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/b91884a97a74eee3d9dde816a107e934550ccf26/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/tools/typescript/ts_definitions.py b/tools/typescript/ts_definitions.py
index 2b56b539..2fa53525 100644
--- a/tools/typescript/ts_definitions.py
+++ b/tools/typescript/ts_definitions.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import argparse
+import collections
 import json
 import os
 import re
@@ -51,11 +52,9 @@
 
   # Handle custom path mappings, for example chrome://resources/ URLs.
   if args.path_mappings is not None:
-    path_mappings = {}
+    path_mappings = collections.defaultdict(list)
     for m in args.path_mappings:
       mapping = m.split('|')
-      if not path_mappings.has_key(mapping[0]):
-        path_mappings[mapping[0]] = []
       path_mappings[mapping[0]].append(os.path.join('./', mapping[1]))
     tsconfig['compilerOptions']['paths'] = path_mappings
 
diff --git a/tools/typescript/ts_library.py b/tools/typescript/ts_library.py
index aab178c1..4f04b48 100644
--- a/tools/typescript/ts_library.py
+++ b/tools/typescript/ts_library.py
@@ -3,11 +3,11 @@
 # found in the LICENSE file.
 
 import argparse
+import collections
 import json
 import os
 import re
 import sys
-from collections import OrderedDict
 
 _CWD = os.getcwd()
 _HERE_DIR = os.path.dirname(__file__)
@@ -44,13 +44,13 @@
   out_dir = os.path.relpath(args.out_dir, args.gen_dir)
   TSCONFIG_BASE_PATH = os.path.join(_HERE_DIR, 'tsconfig_base.json')
 
-  tsconfig = OrderedDict()
+  tsconfig = collections.OrderedDict()
 
   tsconfig['extends'] = args.tsconfig_base \
       if args.tsconfig_base is not None \
       else os.path.relpath(TSCONFIG_BASE_PATH, args.gen_dir)
 
-  tsconfig['compilerOptions'] = OrderedDict()
+  tsconfig['compilerOptions'] = collections.OrderedDict()
   tsconfig['compilerOptions']['tsBuildInfoFile'] = 'tsconfig.tsbuildinfo'
   tsconfig['compilerOptions']['rootDir'] = root_dir
   tsconfig['compilerOptions']['outDir'] = out_dir
@@ -69,11 +69,9 @@
 
   # Handle custom path mappings, for example chrome://resources/ URLs.
   if args.path_mappings is not None:
-    path_mappings = {}
+    path_mappings = collections.defaultdict(list)
     for m in args.path_mappings:
       mapping = m.split('|')
-      if not path_mappings.has_key(mapping[0]):
-        path_mappings[mapping[0]] = []
       path_mappings[mapping[0]].append(os.path.join('./', mapping[1]))
     tsconfig['compilerOptions']['paths'] = path_mappings
 
diff --git a/ui/accessibility/PRESUBMIT.py b/ui/accessibility/PRESUBMIT.py
index c97381a..e61f4cb 100644
--- a/ui/accessibility/PRESUBMIT.py
+++ b/ui/accessibility/PRESUBMIT.py
@@ -34,6 +34,9 @@
     # Strip out comments
     line = re.sub('//.*', '', line)
 
+    # Strip out mojo annotations.
+    line = re.sub('\[(.*)\]', '', line)
+
     # Look for lines of the form "enum ENUM_NAME {" and get the enum_name
     m = re.search('enum ([\w]+) {', line)
     if m:
diff --git a/ui/accessibility/ax_enums.mojom b/ui/accessibility/ax_enums.mojom
index 4337a55..5097998 100644
--- a/ui/accessibility/ax_enums.mojom
+++ b/ui/accessibility/ax_enums.mojom
@@ -25,68 +25,73 @@
 // If unspecified, the attribute is used across web and native on multiple
 // platforms.
 
+// Next version: 1
+// Next value: 59
+[Extensible, Stable, Uuid="686e661e-f8c7-4214-8713-1f66d95d3ffa"]
 enum Event {
-  kNone,
-  kActiveDescendantChanged,
-  kAlert,
-  kAriaAttributeChanged,   // Implicit
-  kAutocorrectionOccured,  // Unknown: http://crbug.com/392498
-  kBlur,                   // Remove: http://crbug.com/392502
-  kCheckedStateChanged,    // Implicit
-  kChildrenChanged,
-  kClicked,
-  kControlsChanged,
-  kDocumentSelectionChanged,
-  kDocumentTitleChanged,
-  kEndOfTest,        // Sentinel value indicating the end of a test
-  kExpandedChanged,  // Web
-  kFocus,
-  kFocusAfterMenuClose,
-  kFocusContext,  // Contextual focus event that must delay the next focus event
-  kHide,          // Remove: http://crbug.com/392502
-  kHitTestResult,
-  kHover,
-  kImageFrameUpdated,     // Web
-  kLayoutComplete,        // Web
-  kLiveRegionCreated,     // Implicit
-  kLiveRegionChanged,     // Web
-  kLoadComplete,          // Web
-  kLoadStart,             // Web / AuraLinux
-  kLocationChanged,       // Web
-  kMediaStartedPlaying,   // Native / Automation
-  kMediaStoppedPlaying,   // Native / Automation
-  kMenuEnd,               // Native / web: menu interaction has ended.
-  kMenuListValueChanged,  // Web
-  kMenuPopupEnd,          // Native / web: a menu/submenu is hidden/closed.
-  kMenuPopupStart,        // Native / web: a menu/submenu is shown/opened.
-  kMenuStart,             // Native / web: menu interaction has begun.
-  kMouseCanceled,
-  kMouseDragged,
-  kMouseMoved,
-  kMousePressed,
-  kMouseReleased,
-  kRowCollapsed,
-  kRowCountChanged,
-  kRowExpanded,
-  kScrollPositionChanged,    // Web
-  kScrolledToAnchor,         // Web
-  kSelectedChildrenChanged,  // Web
-  kSelection,                // Native
-  kSelectionAdd,             // Native
-  kSelectionRemove,          // Native
-  kShow,                     // Native / Automation
-  kStateChanged,             // Native / Automation
-  kTextChanged,
+  [Default]kNone = 0,
+  kActiveDescendantChanged = 1,
+  kAlert = 2,
+  kAriaAttributeChanged = 3,   // Implicit
+  kAutocorrectionOccured = 4,  // Unknown: http://crbug.com/392498
+  kBlur = 5,                   // Remove: http://crbug.com/392502
+  kCheckedStateChanged = 6,    // Implicit
+  kChildrenChanged = 7,
+  kClicked = 8,
+  kControlsChanged = 9,
+  kDocumentSelectionChanged = 10,
+  kDocumentTitleChanged = 11,
+  kEndOfTest = 12,        // Sentinel value indicating the end of a test
+  kExpandedChanged = 13,  // Web
+  kFocus = 14,
+  kFocusAfterMenuClose = 15,
+
+  // Contextual focus event that must delay the next focus event.
+  kFocusContext = 16,
+  kHide = 17,          // Remove: http://crbug.com/392502
+  kHitTestResult = 18,
+  kHover = 19,
+  kImageFrameUpdated = 20,     // Web
+  kLayoutComplete = 21,        // Web
+  kLiveRegionCreated = 22,     // Implicit
+  kLiveRegionChanged = 23,     // Web
+  kLoadComplete = 24,          // Web
+  kLoadStart = 25,             // Web / AuraLinux
+  kLocationChanged = 26,       // Web
+  kMediaStartedPlaying = 27,   // Native / Automation
+  kMediaStoppedPlaying = 28,   // Native / Automation
+  kMenuEnd = 29,               // Native / web: menu interaction has ended.
+  kMenuListValueChanged = 30,  // Web
+  kMenuPopupEnd = 31,          // Native / web: a menu/submenu is hidden/closed.
+  kMenuPopupStart = 32,        // Native / web: a menu/submenu is shown/opened.
+  kMenuStart = 33,             // Native / web: menu interaction has begun.
+  kMouseCanceled = 34,
+  kMouseDragged = 35,
+  kMouseMoved = 36,
+  kMousePressed = 37,
+  kMouseReleased = 38,
+  kRowCollapsed = 39,
+  kRowCountChanged = 40,
+  kRowExpanded = 41,
+  kScrollPositionChanged = 42,    // Web
+  kScrolledToAnchor = 43,         // Web
+  kSelectedChildrenChanged = 44,  // Web
+  kSelection = 45,                // Native
+  kSelectionAdd = 46,             // Native
+  kSelectionRemove = 47,          // Native
+  kShow = 48,                     // Native / Automation
+  kStateChanged = 49,             // Native / Automation
+  kTextChanged = 50,
   // TODO(nektar): Remove kTextSelectionChanged.
-  kTextSelectionChanged,
-  kTooltipClosed,
-  kTooltipOpened,
-  kTreeChanged,  // Don't explicitly fire this event.
+  kTextSelectionChanged = 51,
+  kTooltipClosed = 52,
+  kTooltipOpened = 53,
+  kTreeChanged = 54,  // Don't explicitly fire this event.
   // TODO(nektar): Remove kValueChanged.
-  kValueChanged,
-  kWindowActivated,             // Native
-  kWindowDeactivated,           // Native
-  kWindowVisibilityChanged,     // Native
+  kValueChanged = 55,
+  kWindowActivated = 56,             // Native
+  kWindowDeactivated = 57,           // Native
+  kWindowVisibilityChanged = 58,     // Native
 };
 
 // Accessibility object roles.
@@ -331,102 +336,105 @@
 // An action to be taken on an accessibility node.
 // In contrast to |AXDefaultActionVerb|, these describe what happens to the
 // object, e.g. "FOCUS".
+// Next version: 1
+// Next value: 33
+[Extensible, Stable, Uuid="ed8e4466-0522-4f98-ac28-59a523b70232"]
 enum Action {
-  kNone,
+  [Default]kNone = 0,
 
   // Request image annotations for all the eligible images on a page.
-  kAnnotatePageImages,
+  kAnnotatePageImages = 1,
 
-  kBlur,
+  kBlur = 2,
 
   // Notifies a node that it no longer has accessibility focus.
   // Currently used only on Android and only internally, it's not
   // exposed to the open web. See kSetAccessibilityFocus, below.
-  kClearAccessibilityFocus,
+  kClearAccessibilityFocus = 3,
 
   // Collapse the collapsible node.
-  kCollapse,
+  kCollapse = 4,
 
-  kCustomAction,
+  kCustomAction = 5,
 
   // Decrement a slider or range control by one step value.
-  kDecrement,
+  kDecrement = 6,
 
   // Do the default action for an object, typically this means "click".
-  kDoDefault,
+  kDoDefault = 7,
 
   // Expand the expandable node.
-  kExpand,
+  kExpand = 8,
 
-  kFocus,
+  kFocus = 9,
 
   // Return the content of this image object in the image_data attribute.
-  kGetImageData,
+  kGetImageData = 10,
 
   // Gets the bounding rect for a range of text.
-  kGetTextLocation,
+  kGetTextLocation = 11,
 
-  kHideTooltip,
+  kHideTooltip = 12,
 
   // Given a point, find the object it corresponds to and fire a
   // |AXActionData.hit_test_event_to_fire| event on it in response.
-  kHitTest,
+  kHitTest = 13,
 
   // Increment a slider or range control by one step value.
-  kIncrement,
+  kIncrement = 14,
 
   // For internal use only; signals to tree sources to invalidate an entire
   // tree.
-  kInternalInvalidateTree,
+  kInternalInvalidateTree = 15,
 
   // Load inline text boxes for this subtree, providing information
   // about word boundaries, line layout, and individual character
   // bounding boxes.
-  kLoadInlineTextBoxes,
+  kLoadInlineTextBoxes = 16,
 
   // Delete any selected text in the control's text value and
   // insert |AXActionData::value| in its place, like when typing or pasting.
-  kReplaceSelectedText,
+  kReplaceSelectedText = 17,
 
   // Scrolls by approximately one screen in a specific direction. Should be
   // called on a node that has scrollable boolean set to true.
-  kScrollBackward,
-  kScrollDown,
-  kScrollForward,
-  kScrollLeft,
-  kScrollRight,
-  kScrollUp,
+  kScrollBackward = 18,
+  kScrollDown = 19,
+  kScrollForward = 20,
+  kScrollLeft = 21,
+  kScrollRight = 22,
+  kScrollUp = 23,
 
   // Scroll any scrollable containers to make the target object visible
   // on the screen.  Optionally pass a subfocus rect in
   // AXActionData.target_rect, in node-local coordinates.
-  kScrollToMakeVisible,
+  kScrollToMakeVisible = 24,
 
   // Scroll the given object to a specified point on the screen in
   // global screen coordinates. Pass a point in AXActionData.target_point.
-  kScrollToPoint,
+  kScrollToPoint = 25,
 
   // Notifies a node that it has accessibility focus.
   // Currently used only on Android and only internally, it's not
   // exposed to the open web. See kClearAccessibilityFocus, above.
-  kSetAccessibilityFocus,
+  kSetAccessibilityFocus = 26,
 
-  kSetScrollOffset,
-  kSetSelection,
+  kSetScrollOffset = 27,
+  kSetSelection = 28,
 
   // Don't focus this node, but set it as the sequential focus navigation
   // starting point, so that pressing Tab moves to the next element
   // following this one, for example.
-  kSetSequentialFocusNavigationStartingPoint,
+  kSetSequentialFocusNavigationStartingPoint = 29,
 
   // Replace the value of the control with AXActionData::value and
   // reset the selection, if applicable.
-  kSetValue,
-  kShowContextMenu,
+  kSetValue = 30,
+  kShowContextMenu = 31,
 
   // Send an event signaling the end of a test.
-  kSignalEndOfTest,
-  kShowTooltip,
+  kSignalEndOfTest = 32,
+  kShowTooltip = 33,
 };
 
 enum ActionFlags {
@@ -438,23 +446,28 @@
 // A list of valid values for the horizontal and vertical scroll alignment
 // arguments in |AXActionData|. These values control where a node is scrolled
 // in the viewport.
+// Next version: 1
+// Next value: 6
+[Extensible, Stable, Uuid="a9d4f137-4f2e-4533-a4ac-cabdc433ecee"]
 enum ScrollAlignment {
-  kNone,
-  kScrollAlignmentCenter,
-  kScrollAlignmentTop,
-  kScrollAlignmentBottom,
-  kScrollAlignmentLeft,
-  kScrollAlignmentRight,
-  kScrollAlignmentClosestEdge
+  [Default]kNone = 0,
+  kScrollAlignmentCenter = 1,
+  kScrollAlignmentTop = 2,
+  kScrollAlignmentBottom = 3,
+  kScrollAlignmentLeft = 4,
+  kScrollAlignmentRight = 5,
+  kScrollAlignmentClosestEdge = 6
 };
 
 // A list of valid values for the scroll behavior argument to argument in
 // |AXActionData|. These values control whether a node is scrolled in the
 // viewport if it is already visible.
+// Next version: 1
+[Extensible, Stable, Uuid="8bf2a1cb-2edb-4e41-8d7e-a6c8baa95c85"]
 enum ScrollBehavior {
-  kNone,
-  kDoNotScrollIfVisible,
-  kScrollIfVisible,
+  [Default]kNone = 0,
+  kDoNotScrollIfVisible = 1,
+  kScrollIfVisible = 2,
 };
 
 // A list of valid values for the |AXIntAttribute| |default_action_verb|.
diff --git a/ui/accessibility/mojom/BUILD.gn b/ui/accessibility/mojom/BUILD.gn
index b934284..3302ef74 100644
--- a/ui/accessibility/mojom/BUILD.gn
+++ b/ui/accessibility/mojom/BUILD.gn
@@ -7,7 +7,6 @@
 mojom("mojom") {
   sources = [
     "ax_action_data.mojom",
-    "ax_assistant_structure.mojom",
     "ax_event.mojom",
     "ax_event_intent.mojom",
     "ax_node_data.mojom",
@@ -42,30 +41,6 @@
     {
       types = [
         {
-          mojom = "ax.mojom.AssistantTree"
-          cpp = "::std::unique_ptr<::ui::AssistantTree>"
-          move_only = true
-          nullable_is_same_type = true
-        },
-        {
-          mojom = "ax.mojom.AssistantNode"
-          cpp = "::std::unique_ptr<::ui::AssistantNode>"
-          move_only = true
-        },
-      ]
-      traits_sources = [ "ax_assistant_structure_mojom_traits.cc" ]
-      traits_headers = [ "ax_assistant_structure_mojom_traits.h" ]
-      traits_public_deps = [
-        "//ui/accessibility:ax_assistant",
-        "//ui/gfx",
-        "//ui/gfx/geometry/mojom",
-        "//ui/gfx/geometry/mojom:mojom_traits",
-        "//ui/gfx/range/mojom",
-      ]
-    },
-    {
-      types = [
-        {
           mojom = "ax.mojom.AXEventIntent"
           cpp = "::ui::AXEventIntent"
         },
@@ -147,3 +122,41 @@
     },
   ]
 }
+mojom("ax_assistant_mojom") {
+  sources = [ "ax_assistant_structure.mojom" ]
+
+  cpp_typemaps = [
+    {
+      types = [
+        {
+          mojom = "ax.mojom.AssistantTree"
+          cpp = "::std::unique_ptr<::ui::AssistantTree>"
+          move_only = true
+          nullable_is_same_type = true
+        },
+        {
+          mojom = "ax.mojom.AssistantNode"
+          cpp = "::std::unique_ptr<::ui::AssistantNode>"
+          move_only = true
+        },
+      ]
+      traits_sources = [ "ax_assistant_structure_mojom_traits.cc" ]
+      traits_headers = [ "ax_assistant_structure_mojom_traits.h" ]
+      traits_public_deps = [
+        "//ui/accessibility:ax_assistant",
+        "//ui/gfx",
+        "//ui/gfx/geometry/mojom",
+        "//ui/gfx/geometry/mojom:mojom_traits",
+        "//ui/gfx/range/mojom",
+      ]
+    },
+  ]
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+    "//ui/gfx/geometry/mojom",
+    "//ui/gfx/mojom",
+    "//ui/gfx/range/mojom",
+    "//url/mojom:url_mojom_gurl",
+  ]
+}
diff --git a/ui/accessibility/mojom/ax_action_data.mojom b/ui/accessibility/mojom/ax_action_data.mojom
index d802f4a..cc835a2 100644
--- a/ui/accessibility/mojom/ax_action_data.mojom
+++ b/ui/accessibility/mojom/ax_action_data.mojom
@@ -10,6 +10,8 @@
 
 // A compact representation of an accessibility action and the arguments
 // associated with that action. See ui::AXActionData for full documentation.
+// Next version: 1
+[Stable, Uuid="977807b3-17e0-4186-8398-deae1aeba2ec"]
 struct AXActionData {
   Action action;
   ax.mojom.AXTreeID target_tree_id;
diff --git a/ui/accessibility/mojom/ax_tree_id.mojom b/ui/accessibility/mojom/ax_tree_id.mojom
index 0f3c7943..6b37621 100644
--- a/ui/accessibility/mojom/ax_tree_id.mojom
+++ b/ui/accessibility/mojom/ax_tree_id.mojom
@@ -7,6 +7,8 @@
 import "ui/accessibility/ax_enums.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 
+// Next version: 1
+[Stable, Uuid="8bc56bf8-a206-42b2-970f-60347a23e7fa"]
 union AXTreeID {
   // Placeholder for an unknown AXTreeID. The value of this field is not used.
   uint8 unknown;
diff --git a/ui/android/DIR_METADATA b/ui/android/DIR_METADATA
index fdda50b..048a7e5 100644
--- a/ui/android/DIR_METADATA
+++ b/ui/android/DIR_METADATA
@@ -6,7 +6,4 @@
 # For the schema of this file, see Metadata message:
 #   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
 
-monorail {
-  component: "UI"
-}
 os: ANDROID
\ No newline at end of file
diff --git a/ui/android/java/res/DIR_METADATA b/ui/android/java/res/DIR_METADATA
index 94bd7e2..263fe7d 100644
--- a/ui/android/java/res/DIR_METADATA
+++ b/ui/android/java/res/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "UI>Browser>Mobile"
 }
-os: ANDROID
\ No newline at end of file
diff --git a/ui/android/java/res_night/DIR_METADATA b/ui/android/java/res_night/DIR_METADATA
index 94bd7e2..263fe7d 100644
--- a/ui/android/java/res_night/DIR_METADATA
+++ b/ui/android/java/res_night/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "UI>Browser>Mobile"
 }
-os: ANDROID
\ No newline at end of file
diff --git a/ui/android/java/src/org/chromium/ui/base/DIR_METADATA b/ui/android/java/src/org/chromium/ui/base/DIR_METADATA
deleted file mode 100644
index 2769d07..0000000
--- a/ui/android/java/src/org/chromium/ui/base/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI"
-}
\ No newline at end of file
diff --git a/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA b/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
index 549f1c28..b311cbf8 100644
--- a/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
+++ b/ui/android/java/src/org/chromium/ui/modaldialog/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "UI>Browser>Mobile>Messages"
 }
-os: ANDROID
diff --git a/ui/android/java/src/org/chromium/ui/modelutil/DIR_METADATA b/ui/android/java/src/org/chromium/ui/modelutil/DIR_METADATA
index 94bd7e2..263fe7d 100644
--- a/ui/android/java/src/org/chromium/ui/modelutil/DIR_METADATA
+++ b/ui/android/java/src/org/chromium/ui/modelutil/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "UI>Browser>Mobile"
 }
-os: ANDROID
\ No newline at end of file
diff --git a/ui/android/junit/src/org/chromium/ui/base/DIR_METADATA b/ui/android/junit/src/org/chromium/ui/base/DIR_METADATA
deleted file mode 100644
index 2769d07..0000000
--- a/ui/android/junit/src/org/chromium/ui/base/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI"
-}
\ No newline at end of file
diff --git a/ui/android/junit/src/org/chromium/ui/modaldialog/DIR_METADATA b/ui/android/junit/src/org/chromium/ui/modaldialog/DIR_METADATA
index 94bd7e2..263fe7d 100644
--- a/ui/android/junit/src/org/chromium/ui/modaldialog/DIR_METADATA
+++ b/ui/android/junit/src/org/chromium/ui/modaldialog/DIR_METADATA
@@ -9,4 +9,3 @@
 monorail {
   component: "UI>Browser>Mobile"
 }
-os: ANDROID
\ No newline at end of file
diff --git a/ui/base/cocoa/DIR_METADATA b/ui/base/cocoa/DIR_METADATA
deleted file mode 100644
index 2769d07..0000000
--- a/ui/base/cocoa/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "UI"
-}
\ No newline at end of file
diff --git a/ui/chromeos/DIR_METADATA b/ui/chromeos/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/chromeos/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/chromeos/colors/DIR_METADATA b/ui/chromeos/colors/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/chromeos/colors/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/color/DIR_METADATA b/ui/color/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/color/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index ea8c813..9f3cca8 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -267,6 +267,7 @@
     "//testing/gtest",
     "//ui/base",
     "//ui/gfx",
+    "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//ui/gl",
     "//ui/resources",
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index cbe9e13..4169b58a 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -64,6 +64,7 @@
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/interpolated_transform.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/test/gfx_util.h"
 
 using cc::MatchesPNGFile;
 using cc::WritePNGFile;
@@ -108,10 +109,9 @@
 class LayerWithRealCompositorTest : public testing::TestWithParam<bool> {
  public:
   LayerWithRealCompositorTest()
-      : task_environment_(base::test::TaskEnvironment::MainThreadType::UI) {
-    gfx::FontList::SetDefaultFontDescription("Segoe UI, 15px");
-  }
-  ~LayerWithRealCompositorTest() override {}
+      : task_environment_(base::test::TaskEnvironment::MainThreadType::UI),
+        default_font_desc_setter_("Segoe UI, 15px") {}
+  ~LayerWithRealCompositorTest() override = default;
 
   // Overridden from testing::Test:
   void SetUp() override {
@@ -251,6 +251,8 @@
   // The root directory for test files.
   base::FilePath test_data_dir_;
 
+  gfx::ScopedDefaultFontDescription default_font_desc_setter_;
+
   DISALLOW_COPY_AND_ASSIGN(LayerWithRealCompositorTest);
 };
 
diff --git a/ui/events/event.cc b/ui/events/event.cc
index 8f8c5828..b55d5ba 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -152,6 +152,11 @@
 }
 #endif  // defined(USE_OZONE)
 
+bool IsNearZero(const float num) {
+  // Epsilon of 1e-10 at 0.
+  return (std::fabs(num) < 1e-10);
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -773,6 +778,26 @@
                             pointer_details_.radius_y * matrix.get(1, 1));
   pointer_details_.radius_x = new_x;
   pointer_details_.radius_y = new_y;
+
+  // for stylus touches, tilt needs to be rotated appropriately. We don't handle
+  // screen rotations other than 0/90/180/270, but those should be handled and
+  // translated appropriately. Other rotations leave tilts untouched for now. We
+  // add a small check that tilt is set at all before looking through this
+  // section.
+  if (!IsNearZero(pointer_details_.tilt_x) ||
+      !IsNearZero(pointer_details_.tilt_y)) {
+    if (IsNearZero(matrix.get(0, 1)) && IsNearZero(matrix.get(1, 0))) {
+      pointer_details_.tilt_x *= std::copysign(1, matrix.get(0, 0));
+      pointer_details_.tilt_y *= std::copysign(1, matrix.get(1, 1));
+    } else if (IsNearZero(matrix.get(0, 0)) && IsNearZero(matrix.get(1, 1))) {
+      double new_tilt_x =
+          pointer_details_.tilt_y * std::copysign(1, matrix.get(0, 1));
+      double new_tilt_y =
+          pointer_details_.tilt_x * std::copysign(1, matrix.get(1, 0));
+      pointer_details_.tilt_x = new_tilt_x;
+      pointer_details_.tilt_y = new_tilt_y;
+    }
+  }
 }
 
 void TouchEvent::DisableSynchronousHandling() {
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index e081b9ba43..ade042b 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -705,7 +705,9 @@
     gfx::Transform transform3x;
     transform3x.Scale(3, 3);
     PointerDetails pointer_details(EventPointerType::kTouch, 0 /* pointer id */,
-                                   3, 4, 50, 0 /* twist */, 0, 0);
+                                   3, 4, 50, 0 /* twist */, 17.2 /* tilt_x */,
+                                   -28.3 /* tilt_y */);
+
     ui::TouchEvent targeted(ET_TOUCH_PRESSED, f_location, f_root_location,
                             EventTimeForNow(), pointer_details);
     targeted.UpdateForRootTransform(transform2x, transform3x);
@@ -733,7 +735,9 @@
     gfx::Transform transform3x;
     transform3x.Scale(3, 3);
     PointerDetails pointer_details(EventPointerType::kTouch, 0 /* pointer id */,
-                                   3, 4, 50, 0 /* twist */, 0, 0);
+                                   3, 4, 50, 0 /* twist */, -17.4 /* tilt_x */,
+                                   31.2 /* tilt_y */);
+
     ui::TouchEvent targeted(ET_TOUCH_PRESSED, f_location, f_root_location,
                             EventTimeForNow(), pointer_details);
     Event::DispatcherApi(&targeted).set_target(&target);
@@ -741,6 +745,9 @@
     auto updated_pointer_details(pointer_details);
     updated_pointer_details.radius_x = pointer_details.radius_y * 0.75;
     updated_pointer_details.radius_y = pointer_details.radius_x * 0.5;
+    updated_pointer_details.tilt_x = -31.2;
+    updated_pointer_details.tilt_y = -17.4;
+
     EXPECT_EQ(updated_pointer_details, targeted.pointer_details())
         << " orig: " << updated_pointer_details.ToString() << " vs "
         << targeted.pointer_details().ToString();
diff --git a/ui/file_manager/BUILD.gn b/ui/file_manager/BUILD.gn
index 3b98ae9..a842f79 100644
--- a/ui/file_manager/BUILD.gn
+++ b/ui/file_manager/BUILD.gn
@@ -39,7 +39,6 @@
     "audio_player/js:closure_compile",
     "file_manager/background/js:closure_compile",
     "file_manager/common/js:closure_compile",
-    "file_manager/cws_widget:closure_compile",
     "file_manager/foreground/elements:closure_compile",
     "file_manager/foreground/js:closure_compile",
     "file_manager/foreground/js/metadata:closure_compile",
@@ -81,13 +80,20 @@
   out_manifest = "$target_gen_dir/manifest_preprocess_static.json"
 
   in_files = [
+    # Audio Player:
     "audio_player/js/main.m.js",
     "audio_player/js/main_background.m.js",
+
+    # Files app:
     "file_manager/background/js/main_background.m.js",
     "file_manager/foreground/js/deferred_elements.m.js",
     "file_manager/foreground/js/elements_importer.m.js",
     "file_manager/foreground/js/main.m.js",
+
+    # Image Loader:
     "image_loader/background.m.js",
+
+    # Video Player:
     "video_player/js/main.m.js",
     "video_player/js/main_background.m.js",
   ]
@@ -117,11 +123,11 @@
     "audio_player/js/background.m.js",
     "audio_player/js/audio_player.m.js",
     "audio_player/js/metadata_worker.m.js",
-    "audio_player/elements/audio_player.m.js",
+    "audio_player/elements/audio_player.js",
     "audio_player/elements/track_info_panel.js",
-    "audio_player/elements/track_list.m.js",
-    "audio_player/elements/control_panel.m.js",
-    "audio_player/elements/repeat_button.m.js",
+    "audio_player/elements/track_list.js",
+    "audio_player/elements/control_panel.js",
+    "audio_player/elements/repeat_button.js",
 
     # Common:
     "file_manager/common/js/app_util.m.js",
@@ -257,7 +263,6 @@
     "file_manager/foreground/js/task_history.m.js",
     "file_manager/foreground/js/thumbnail_loader.m.js",
     "file_manager/foreground/js/toolbar_controller.m.js",
-    "file_manager/foreground/js/web_store_utils.m.js",
     "file_manager/foreground/js/webui_command_extender.m.js",
 
     # Files app Elements:
@@ -322,13 +327,6 @@
     "file_manager/foreground/js/ui/table/table_list.m.js",
     "file_manager/foreground/js/ui/table/table_splitter.m.js",
 
-    # CWS:
-    "file_manager/cws_widget/app_installer.m.js",
-    "file_manager/cws_widget/cws_webview_client.m.js",
-    "file_manager/cws_widget/cws_widget_container.m.js",
-    "file_manager/cws_widget/cws_widget_container_error_dialog.m.js",
-    "file_manager/cws_widget/cws_widget_container_platform_delegate.m.js",
-
     # Image Loader:
     "image_loader/cache.m.js",
     "image_loader/image_loader.m.js",
@@ -373,13 +371,11 @@
   ]
 
   deps = [
-    "//ui/file_manager/audio_player/elements:elements",
     "//ui/file_manager/audio_player/elements:web_components",
     "//ui/file_manager/audio_player/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",
-    "//ui/file_manager/file_manager/cws_widget:modulize",
     "//ui/file_manager/file_manager/externs:modulize",
     "//ui/file_manager/file_manager/externs/background:modulize",
     "//ui/file_manager/file_manager/foreground/elements:elements",
diff --git a/ui/file_manager/audio_player/audio_player.html b/ui/file_manager/audio_player/audio_player.html
deleted file mode 100644
index fb58922..0000000
--- a/ui/file_manager/audio_player/audio_player.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  -- Copyright 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.
-  -->
-<!DOCTYPE HTML>
-<html>
-<head>
-  <!-- We have to set some default title, or chrome will use the page name.
-    -- As soon as the i18n'd strings are loaded we replace it with the correct
-    -- string. Until then, use an invisible non-whitespace character.
-    -->
-  <title>&#xFEFF;</title>
-  <script src="chrome://resources/polymer/v1_0/html-imports/html-imports.min.js"></script>
-  <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-  <link rel="stylesheet" type="text/css" href="css/audio_player.css">
-
-  <script src="chrome://resources/js/assert.js"></script>
-  <script src="chrome://resources/js/load_time_data.js"></script>
-  <script src="chrome://resources/js/util.js"></script>
-
-  <link rel="import" href="elements/audio_player.html">
-  <script src="js/audio_player_scripts.js"></script>
-</head>
-<body>
-  <custom-style>
-    <style>
-      html {
-        /* Customize control-panel buttons. */
-        --files-ripple-bg-color: black;
-        --files-toggle-ripple-bg-color: black;
-        --files-toggle-ripple-activated-bg-color: black;
-        --files-toggle-ripple-activated-opacity: 0.1;
-      }
-    </style>
-  </custom-style>
-  <div class="audio-player">
-    <!-- Place the audio player. -->
-    <audio-player></audio-player>
-  </div>
-</body>
-</html>
diff --git a/ui/file_manager/audio_player/elements/BUILD.gn b/ui/file_manager/audio_player/elements/BUILD.gn
index f6a127c..4133890 100644
--- a/ui/file_manager/audio_player/elements/BUILD.gn
+++ b/ui/file_manager/audio_player/elements/BUILD.gn
@@ -3,113 +3,35 @@
 # found in the LICENSE file.
 
 import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/polymer/polymer.gni")
 import("//tools/polymer/html_to_js.gni")
 
 html_to_js("web_components") {
   js_files = [
+    "audio_player.js",
+    "control_panel.js",
     "track_info_panel.js",
-  ]
-}
-
-group("elements") {
-  public_deps = [
-    "//ui/file_manager/audio_player/elements:audio_player_module",
-    "//ui/file_manager/audio_player/elements:control_panel_module",
-    "//ui/file_manager/audio_player/elements:repeat_button_module",
-    "//ui/file_manager/audio_player/elements:track_list_module",
-  ]
-}
-
-group("closure_compile") {
-  deps = [
-    ":closure_compile_internal",
-    ":closure_compile_jsmodules",
-  ]
-}
-
-js_type_check("closure_compile_internal") {
-  uses_legacy_modules = true
-  deps = [
-    ":audio_player",
-    ":control_panel",
-    ":repeat_button",
-    ":track_list",
+    "track_list.js",
+    "repeat_button.js",
   ]
 }
 
 js_library("audio_player") {
   deps = [
     ":control_panel",
-    ":track_list",
-  ]
-}
-
-polymer_modulizer("audio_player") {
-  js_file = "audio_player.js"
-  html_file = "audio_player.html"
-  html_type = "dom-module"
-  preserve_url_scheme = true
-  migrated_imports = [
-    "ui/file_manager/audio_player/elements/track_info_panel.html",
-  ]
-
-  auto_imports = [
-    "ui/file_manager/audio_player/elements/control_panel.html|AriaLabels",
-    "ui/file_manager/audio_player/elements/track_list.html|TrackInfo",
-    "third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state.html|IronControlState",
-  ]
-}
-
-js_library("audio_player.m") {
-  sources = [
-    "$root_gen_dir/ui/file_manager/audio_player/elements/audio_player.m.js",
-  ]
-  deps = [
-    ":control_panel.m",
     ":track_info_panel",
-    ":track_list.m",
+    ":track_list",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
-  extra_deps = [ ":audio_player_module" ]
 }
 
 js_library("control_panel") {
   deps = [
     ":repeat_button",
-    "//ui/webui/resources/cr_elements/cr_slider:cr_slider",
-    "//ui/webui/resources/js:assert",
-  ]
-}
-
-polymer_modulizer("control_panel") {
-  js_file = "control_panel.js"
-  html_file = "control_panel.html"
-  html_type = "dom-module"
-  preserve_url_scheme = true
-
-  auto_imports = [ "ui/webui/resources/html/assert.html|assert" ]
-}
-
-js_library("control_panel.m") {
-  sources = [
-    "$root_gen_dir/ui/file_manager/audio_player/elements/control_panel.m.js",
-  ]
-  deps = [
-    ":repeat_button.m",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/file_manager/file_manager/foreground/elements:files_icon_button.m",
     "//ui/webui/resources/cr_elements/cr_slider:cr_slider.m",
     "//ui/webui/resources/js:assert.m",
   ]
-  extra_deps = [ ":control_panel_module" ]
-}
-
-js_library("repeat_button") {
-  deps = [
-    "//third_party/polymer/v1_0/components-chromium/iron-behaviors:iron-button-state-extracted",
-    "//third_party/polymer/v1_0/components-chromium/iron-behaviors:iron-control-state-extracted",
-  ]
 }
 
 js_library("track_info_panel") {
@@ -120,63 +42,29 @@
 }
 
 js_library("track_list") {
-}
-
-polymer_modulizer("track_list") {
-  js_file = "track_list.js"
-  html_file = "track_list.html"
-  html_type = "dom-module"
-  preserve_url_scheme = true
-}
-
-js_library("track_list.m") {
-  sources =
-      [ "$root_gen_dir/ui/file_manager/audio_player/elements/track_list.m.js" ]
   deps = [
     "//third_party/polymer/v3_0/components-chromium/paper-ripple:paper-ripple",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
   ]
-  extra_deps = [ ":track_list_module" ]
 }
 
-polymer_modulizer("repeat_button") {
-  js_file = "repeat_button.js"
-  html_file = "repeat_button.html"
-  html_type = "dom-module"
-  preserve_url_scheme = true
-
-  namespace_rewrites = [
-    "Polymer.IronButtonState|IronButtonState",
-    "Polymer.IronControlState|IronControlState",
-  ]
-
-  auto_imports = [
-    "third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state.html|IronButtonState",
-    "third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state.html|IronControlState",
-  ]
-}
-
-js_library("repeat_button.m") {
-  sources = [
-    "$root_gen_dir/ui/file_manager/audio_player/elements/repeat_button.m.js",
-  ]
+js_library("repeat_button") {
   deps = [
     "//third_party/polymer/v3_0/components-chromium/iron-behaviors:iron-button-state",
     "//third_party/polymer/v3_0/components-chromium/iron-behaviors:iron-control-state",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/file_manager/file_manager/foreground/elements:files_toggle_ripple.m",
   ]
-  extra_deps = [ ":repeat_button_module" ]
 }
 
-js_type_check("closure_compile_jsmodules") {
+js_type_check("closure_compile") {
   is_polymer3 = true
   closure_flags = default_closure_args + [ "browser_resolver_prefix_replacements=\"chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/=../../ui/file_manager/file_manager/\"" ]
   deps = [
-    ":audio_player.m",
-    ":control_panel.m",
-    ":repeat_button.m",
+    ":audio_player",
+    ":control_panel",
+    ":repeat_button",
     ":track_info_panel",
-    ":track_list.m",
+    ":track_list",
   ]
 }
diff --git a/ui/file_manager/audio_player/elements/audio_player.html b/ui/file_manager/audio_player/elements/audio_player.html
index 6f081e2f..439f7141 100644
--- a/ui/file_manager/audio_player/elements/audio_player.html
+++ b/ui/file_manager/audio_player/elements/audio_player.html
@@ -3,62 +3,50 @@
   -- Use of this source code is governed by a BSD-style license that can be
   -- found in the LICENSE file.
   -->
+<style>
+  :host {
+    display: flex;
+    flex-direction: column;
+    height: 100%;
+    justify-content: space-between;
+  }
 
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="track_info_panel.html">
-<link rel="import" href="track_list.html">
-<link rel="import" href="control_panel.html">
+  track-info-panel {
+    flex-grow: 0;
+    flex-shrink: 0;
+  }
 
-<dom-module id="audio-player">
-  <template>
-    <style>
-      :host {
-        display: flex;
-        flex-direction: column;
-        height: 100%;
-        justify-content: space-between;
-      }
+  track-list {
+    flex-grow: 1;
+    flex-shrink: 1;
+    overflow-x: hidden;
+    overflow-y: scroll;
+  }
 
-      track-info-panel {
-        flex-grow: 0;
-        flex-shrink: 0;
-      }
-
-      track-list {
-        flex-grow: 1;
-        flex-shrink: 1;
-        overflow-x: hidden;
-        overflow-y: scroll;
-      }
-
-      control-panel {
-        height: 96px;
-        flex-shrink: 0;
-      }
-    </style>
-    <track-info-panel id="trackInfo" expanded="{{trackInfoExpanded}}"
-        aria-expand-artwork-label="[[ariaExpandArtworkLabel]]">
-    </track-info-panel>
-    <track-list id="trackList"
-        expanded$="[[playlistExpanded]]"
-        shuffle="[[shuffle]]"
-        current-track-index="{{currentTrackIndex}}"
-        on-replay="onReplayCurrentTrack"
-        on-play="onPlayCurrentTrack"></track-list>
-    <control-panel id="audioController"
-        playing="{{playing}}"
-        time="[[time]]"
-        duration="[[duration]]"
-        shuffle="{{shuffle}}"
-        repeat-mode="{{repeatMode}}"
-        volume="{{volume}}"
-        playlist-expanded="{{playlistExpanded}}"
-        aria-labels="[[ariaLabels]]"
-        on-update-time="onUpdateTime_"
-        on-next-clicked="onControllerNextClicked"
-        on-previous-clicked="onControllerPreviousClicked"></control-panel>
-    <audio id="audio"
-        volume="[[computeAudioVolume_(volume)]]"></audio>
-  </template>
-  <script src="audio_player.js"></script>
-</dom-module>
+  control-panel {
+    height: 96px;
+    flex-shrink: 0;
+  }
+</style>
+<track-info-panel id="trackInfo" expanded="{{trackInfoExpanded}}"
+    aria-expand-artwork-label="[[ariaExpandArtworkLabel]]">
+</track-info-panel>
+<track-list id="trackList"
+    expanded$="[[playlistExpanded]]"
+    shuffle="[[shuffle]]"
+    current-track-index="{{currentTrackIndex}}"
+    on-replay="onReplayCurrentTrack"
+    on-play="onPlayCurrentTrack"></track-list>
+<control-panel id="audioController"
+    playing="{{playing}}"
+    time="[[time]]"
+    duration="[[duration]]"
+    shuffle="{{shuffle}}"
+    repeat-mode="{{repeatMode}}"
+    volume="{{volume}}"
+    playlist-expanded="{{playlistExpanded}}"
+    aria-labels="[[ariaLabels]]"
+    on-update-time="onUpdateTime_"
+    on-next-clicked="onControllerNextClicked"
+    on-previous-clicked="onControllerPreviousClicked"></control-panel>
+<audio id="audio" volume="[[computeAudioVolume_(volume)]]"></audio>
diff --git a/ui/file_manager/audio_player/elements/audio_player.js b/ui/file_manager/audio_player/elements/audio_player.js
index 3b6adeaa..3f41266 100644
--- a/ui/file_manager/audio_player/elements/audio_player.js
+++ b/ui/file_manager/audio_player/elements/audio_player.js
@@ -2,7 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import './track_info_panel.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {AriaLabels} from './control_panel.js';
+import {TrackInfo} from './track_list.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
+
   is: 'audio-player',
 
   listeners: {
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html
index 18a3a228..45b7206 100644
--- a/ui/file_manager/audio_player/elements/control_panel.html
+++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -4,275 +4,264 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_slider/cr_slider.html">
-<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html">
-<link rel="import" href="repeat_button.html">
+<style>
+  /* Controls bar. */
+  .controls {
+    align-items: center;
+    background-color: white;
+    display: flex;
+    flex-direction: column;
+    height: 96px;
+    justify-content: center;
+    padding: 0;
+  }
 
-<dom-module id="control-panel">
-  <template>
-    <style>
-      /* Controls bar. */
-      .controls {
-        align-items: center;
-        background-color: white;
-        display: flex;
-        flex-direction: column;
-        height: 96px;
-        justify-content: center;
-        padding: 0;
-      }
+  .controls .upper-controls,
+  .controls .lower-controls {
+    box-sizing: border-box;
+    height: 48px;
+    padding: 8px;
+    width: 100%;
+  }
 
-      .controls .upper-controls,
-      .controls .lower-controls {
-        box-sizing: border-box;
-        height: 48px;
-        padding: 8px;
-        width: 100%;
-      }
+  .audio-controls {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    padding: 0;
+  }
 
-      .audio-controls {
-        align-items: center;
-        display: flex;
-        flex-direction: row;
-        justify-content: center;
-        padding: 0;
-      }
+  /* Customized scrollbar for the playlist. */
 
-      /* Customized scrollbar for the playlist. */
+  .media-button {
+    background-color: transparent;
+    border: 0;
+    flex: none;
+    height: 32px;
+    outline: none;  /* TODO(yoshiki): Show outline only on keyboard focus. */
+    padding: 0;
+    position: relative;
+    width: 32px;
+  }
 
-      .media-button {
-        background-color: transparent;
-        border: 0;
-        flex: none;
-        height: 32px;
-        outline: none;  /* TODO(yoshiki): Show outline only on keyboard focus. */
-        padding: 0;
-        position: relative;
-        width: 32px;
-      }
+  .media-button > div,
+  .media-button.toggle > label > span {
+    background-position: center;
+    background-repeat: no-repeat;
+    display: inline-block;
+    height: 100%;
+    pointer-events: none;
+    transition: opacity 100ms linear;
+    width: 100%;
+  }
 
-      .media-button > div,
-      .media-button.toggle > label > span {
-        background-position: center;
-        background-repeat: no-repeat;
-        display: inline-block;
-        height: 100%;
-        pointer-events: none;
-        transition: opacity 100ms linear;
-        width: 100%;
-      }
+  .media-button > div {
+    left: 0;
+    opacity: 0;
+    position: absolute;
+    top: 0;
+  }
 
-      .media-button > div {
-        left: 0;
-        opacity: 0;
-        position: absolute;
-        top: 0;
-      }
+  /* Time and volume controls. */
 
-      /* Time and volume controls. */
+  .time-volume-controls {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+    height: 100%;
+    justify-content: center;
+  }
 
-      .time-volume-controls {
-        align-items: center;
-        display: flex;
-        flex-direction: row;
-        height: 100%;
-        justify-content: center;
-      }
+  .time-volume-controls > .time-container {
+    color: rgb(51, 51, 51);
+    cursor: default;
+    flex: none;
+    font-size: 12px;
+    padding: 8px;
+    position: relative;
+  }
 
-      .time-volume-controls > .time-container {
-        color: rgb(51, 51, 51);
-        cursor: default;
-        flex: none;
-        font-size: 12px;
-        padding: 8px;
-        position: relative;
-      }
+  .time-container > .time {
+    position: absolute;
+    right: 8px; /* Should be same as time-container's right padding. */
+    top: 8px; /* Should be same as time-container's top padding. */
+  }
 
-      .time-container > .time {
-        position: absolute;
-        right: 8px; /* Should be same as time-container's right padding. */
-        top: 8px; /* Should be same as time-container's top padding. */
-      }
+  .time-container > .time-spacer {
+    opacity: 0; /* This class is intended to be used as invisible spacer. */
+  }
 
-      .time-container > .time-spacer {
-        opacity: 0; /* This class is intended to be used as invisible spacer. */
-      }
+  .time-volume-controls > cr-slider {
+    --cr-slider-active-color: rgb(66, 133, 244);
+    --cr-slider-knob-color-rgb: 64, 138, 241;
+  }
 
-      .time-volume-controls > cr-slider {
-        --cr-slider-active-color: rgb(66, 133, 244);
-        --cr-slider-knob-color-rgb: 64, 138, 241;
-      }
+  cr-slider {
+    cursor: pointer;
+  }
 
-      cr-slider {
-        cursor: pointer;
-      }
+  #timeSlider {
+    flex: 3 1 auto;
+    width: 118px;
+  }
 
-      #timeSlider {
-        flex: 3 1 auto;
-        width: 118px;
-      }
+  #volumeSlider {
+    flex: 1 1 auto;
+    width: 82px;
+  }
 
-      #volumeSlider {
-        flex: 1 1 auto;
-        width: 82px;
-      }
+  /* Media controls in order of appearance. */
 
-      /* Media controls in order of appearance. */
+  .audio-controls {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+    height: 100%;
+    justify-content: center;
+  }
 
-      .audio-controls {
-        align-items: center;
-        display: flex;
-        flex-direction: row;
-        height: 100%;
-        justify-content: center;
-      }
+  /* Play/pause button. */
 
-      /* Play/pause button. */
+  .media-button.toggle input {
+    position: absolute;
+    visibility: hidden;
+  }
 
-      .media-button.toggle input {
-        position: absolute;
-        visibility: hidden;
-      }
+  .media-button.shuffle-mode {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_shuffle.png) 1x,
+        url(../assets/200/player_button_shuffle.png) 2x);
+    pointer-events: auto;
+  }
 
-      .media-button.shuffle-mode {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_shuffle.png) 1x,
-            url(../assets/200/player_button_shuffle.png) 2x);
-        pointer-events: auto;
-      }
+  .media-button.repeat-mode {
+    margin-left: 8px;
+    margin-right: 0;
+  }
 
-      .media-button.repeat-mode {
-        margin-left: 8px;
-        margin-right: 0;
-      }
+  .media-button.play {
+    margin-left: 4px;
+    margin-right: 4px;
+  }
 
-      .media-button.play {
-        margin-left: 4px;
-        margin-right: 4px;
-      }
+  .media-button.play {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_play.png) 1x,
+        url(../assets/200/player_button_play.png) 2x);
+  }
 
-      .media-button.play {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_play.png) 1x,
-            url(../assets/200/player_button_play.png) 2x);
-      }
+  :host([playing]) .media-button.play {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_pause.png) 1x,
+        url(../assets/200/player_button_pause.png) 2x);
+  }
 
-      :host([playing]) .media-button.play {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_pause.png) 1x,
-            url(../assets/200/player_button_pause.png) 2x);
-      }
+  .media-button.previous {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_previous.png) 1x,
+        url(../assets/200/player_button_previous.png) 2x);
+    margin-left: 8px;
+    margin-right: 0;
+  }
 
-      .media-button.previous {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_previous.png) 1x,
-            url(../assets/200/player_button_previous.png) 2x);
-        margin-left: 8px;
-        margin-right: 0;
-      }
+  .media-button.next {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_next.png) 1x,
+        url(../assets/200/player_button_next.png) 2x);
+    margin-left: 0;
+    margin-right: 8px;
+  }
 
-      .media-button.next {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_next.png) 1x,
-            url(../assets/200/player_button_next.png) 2x);
-        margin-left: 0;
-        margin-right: 8px;
-      }
+  .media-button.playlist {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_playlist.png) 1x,
+        url(../assets/200/player_button_playlist.png) 2x);
+    pointer-events: auto;
+  }
 
-      .media-button.playlist {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_playlist.png) 1x,
-            url(../assets/200/player_button_playlist.png) 2x);
-        pointer-events: auto;
-      }
+  .media-button.volume {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_volume.png) 1x,
+        url(../assets/200/player_button_volume.png) 2x);
+    pointer-events: auto;
+  }
 
-      .media-button.volume {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_volume.png) 1x,
-            url(../assets/200/player_button_volume.png) 2x);
-        pointer-events: auto;
-      }
+  :host([volume='0']) .media-button.volume {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_volume_muted.png) 1x,
+        url(../assets/200/player_button_volume_muted.png) 2x);
+  }
 
-      :host([volume='0']) .media-button.volume {
-        background-image: -webkit-image-set(
-            url(../assets/100/player_button_volume_muted.png) 1x,
-            url(../assets/200/player_button_volume_muted.png) 2x);
-      }
+  /* Invisible div used to compute the width required for the elapsed time. */
+  .time-controls > .time > .current {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+    height: 100%;
+    justify-content: flex-end;
+    position: absolute;
+    top: -1px;
+  }
+</style>
+<div class="controls">
+  <div class="upper-controls audio-controls">
+    <!-- Shuffle toggle button in the bottom line. -->
+    <files-icon-button toggles
+        id="shuffle"
+        class="shuffle-mode media-button toggle"
+        active="{{shuffle}}">
+    </files-icon-button>
 
-      /* Invisible div used to compute the width required for the elapsed time. */
-      .time-controls > .time > .current {
-        align-items: center;
-        display: flex;
-        flex-direction: row;
-        height: 100%;
-        justify-content: flex-end;
-        position: absolute;
-        top: -1px;
-      }
-    </style>
-    <div class="controls">
-      <div class="upper-controls audio-controls">
-        <!-- Shuffle toggle button in the bottom line. -->
-        <files-icon-button toggles
-            id="shuffle"
-            class="shuffle-mode media-button toggle"
-            active="{{shuffle}}">
-        </files-icon-button>
+    <!-- RepeatMode toggle button in the bottom line. -->
+    <repeat-button
+        id="repeat"
+        class="repeat-mode media-button"
+        repeat-mode="{{repeatMode}}">
+    </repeat-button>
 
-        <!-- RepeatMode toggle button in the bottom line. -->
-        <repeat-button
-            id="repeat"
-            class="repeat-mode media-button"
-            repeat-mode="{{repeatMode}}">
-        </repeat-button>
+    <!-- Prev button in the bottom line. -->
+    <files-icon-button
+        id="previous"
+        class="previous media-button"
+        on-click="previousClick">
+    </files-icon-button>
 
-        <!-- Prev button in the bottom line. -->
-        <files-icon-button
-            id="previous"
-            class="previous media-button"
-            on-click="previousClick">
-        </files-icon-button>
+    <!-- Play button in the bottom line. -->
+    <files-icon-button
+        id="play"
+        class="play media-button"
+        on-click="playClick">
+    </files-icon-button>
 
-        <!-- Play button in the bottom line. -->
-        <files-icon-button
-            id="play"
-            class="play media-button"
-            on-click="playClick">
-        </files-icon-button>
+    <!-- Next button in the bottom line. -->
+    <files-icon-button
+        id="next"
+        class="next media-button"
+        on-click="nextClick">
+    </files-icon-button>
 
-        <!-- Next button in the bottom line. -->
-        <files-icon-button
-            id="next"
-            class="next media-button"
-            on-click="nextClick">
-        </files-icon-button>
-
-        <!-- Playlist button in the bottom line. -->
-        <files-icon-button toggles
-            id="playList"
-            class="playlist media-button toggle"
-            active="{{playlistExpanded}}">
-        </files-icon-button>
-      </div>
-      <div class="lower-controls time-volume-controls">
-        <!-- Play/pause button and seek slider in the bottom line. -->
-        <div class="time-container">
-          <div class="time-spacer">[[computeTimeString_(duration, duration)]]</div>
-          <div class="time">[[computeTimeString_(time, duration)]]</div>
-        </div>
-        <cr-slider id="timeSlider" max="[[duration]]" value="[[time]]"
-            on-dragging-changed="onSeekingChanged_" no-keybindings></cr-slider>
-        <!-- Volume button and slider in the bottom line. -->
-        <files-icon-button
-            id="volumeButton"
-            class="volume media-button"
-            on-click="volumeClick">
-        </files-icon-button>
-        <cr-slider id="volumeSlider"></cr-slider>
-      </div>
+    <!-- Playlist button in the bottom line. -->
+    <files-icon-button toggles
+        id="playList"
+        class="playlist media-button toggle"
+        active="{{playlistExpanded}}">
+    </files-icon-button>
+  </div>
+  <div class="lower-controls time-volume-controls">
+    <!-- Play/pause button and seek slider in the bottom line. -->
+    <div class="time-container">
+      <div class="time-spacer">[[computeTimeString_(duration, duration)]]</div>
+      <div class="time">[[computeTimeString_(time, duration)]]</div>
     </div>
-  </template>
-  <script src="control_panel.js"></script>
-</dom-module>
+    <cr-slider id="timeSlider" max="[[duration]]" value="[[time]]"
+        on-dragging-changed="onSeekingChanged_" no-keybindings></cr-slider>
+    <!-- Volume button and slider in the bottom line. -->
+    <files-icon-button
+        id="volumeButton"
+        class="volume media-button"
+        on-click="volumeClick">
+    </files-icon-button>
+    <cr-slider id="volumeSlider"></cr-slider>
+  </div>
+</div>
diff --git a/ui/file_manager/audio_player/elements/control_panel.js b/ui/file_manager/audio_player/elements/control_panel.js
index c3ee21a0..6051d45 100644
--- a/ui/file_manager/audio_player/elements/control_panel.js
+++ b/ui/file_manager/audio_player/elements/control_panel.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {assert} from 'chrome://resources/js/assert.m.js';
+import 'chrome://resources/cr_elements/cr_slider/cr_slider.m.js';
+import 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.m.js';
+import './repeat_button.js';
+
+
 /**
  * @typedef {?{
  *   mute: string,
@@ -17,12 +24,11 @@
  *   volumeSlider: string,
  * }}
  */
-/* #export */ let AriaLabels;
-
-(function() {
-/* #ignore */ 'use strict';
+export let AriaLabels;
 
 Polymer({
+  _template: html`{__html_template__}`,
+
   is: 'control-panel',
 
   properties: {
@@ -272,4 +278,3 @@
     this.$.volumeSlider.setAttribute('aria-label', ariaLabels.volumeSlider);
   },
 });
-})();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/elements/repeat_button.html b/ui/file_manager/audio_player/elements/repeat_button.html
index a517b37..c0585f7 100644
--- a/ui/file_manager/audio_player/elements/repeat_button.html
+++ b/ui/file_manager/audio_player/elements/repeat_button.html
@@ -3,53 +3,43 @@
   -- found in the LICENSE file.
   -->
 
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-behaviors/iron-button-state.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-behaviors/iron-control-state.html">
-<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_toggle_ripple.html">
+<style>
+  :host {
+    border-radius: 2px;
+    cursor: pointer;
+    display: inline-block;
+    height: 32px;
+    outline: none;
+    position: relative;
+    width: 32px;
+  }
 
-<dom-module id="repeat-button">
-  <template>
-  <style>
-    :host {
-      border-radius: 2px;
-      cursor: pointer;
-      display: inline-block;
-      height: 32px;
-      outline: none;
-      position: relative;
-      width: 32px;
-    }
+  .repeat-all, .no-repeat {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_repeat.png) 1x,
+        url(../assets/200/player_button_repeat.png) 2x);
+  }
 
-    .repeat-all, .no-repeat {
-      background-image: -webkit-image-set(
-          url(../assets/100/player_button_repeat.png) 1x,
-          url(../assets/200/player_button_repeat.png) 2x);
-    }
+  .repeat-one {
+    background-image: -webkit-image-set(
+        url(../assets/100/player_button_repeat_one.png) 1x,
+        url(../assets/200/player_button_repeat_one.png) 2x);
+  }
 
-    .repeat-one {
-      background-image: -webkit-image-set(
-          url(../assets/100/player_button_repeat_one.png) 1x,
-          url(../assets/200/player_button_repeat_one.png) 2x);
-    }
+  files-toggle-ripple {
+    background-position: center;
+    background-repeat: no-repeat;
+    height: 28px;
+    left: 2px;
+    pointer-events: none;
+    position: absolute;
+    top: 2px;
+    width: 28px;
+  }
 
-    files-toggle-ripple {
-      background-position: center;
-      background-repeat: no-repeat;
-      height: 28px;
-      left: 2px;
-      pointer-events: none;
-      position: absolute;
-      top: 2px;
-      width: 28px;
-    }
-
-    :host(.keyboard-focus) {
-      /* We use box-shadow rather than outline to make it rounded. */
-      box-shadow: 0 0 0 1px rgba(66, 133, 244, 0.5);
-    }
-  </style>
-    <files-toggle-ripple activated="[[isActive(repeatMode)]]" class$="{{repeatMode}}"></files-toggle-ripple>
-  </template>
-  <script src="repeat_button.js"></script>
-</dom-module>
+  :host(.keyboard-focus) {
+    /* We use box-shadow rather than outline to make it rounded. */
+    box-shadow: 0 0 0 1px rgba(66, 133, 244, 0.5);
+  }
+</style>
+<files-toggle-ripple activated="[[isActive(repeatMode)]]" class$="{{repeatMode}}"></files-toggle-ripple>
diff --git a/ui/file_manager/audio_player/elements/repeat_button.js b/ui/file_manager/audio_player/elements/repeat_button.js
index 2b011c1b..09cfc53 100644
--- a/ui/file_manager/audio_player/elements/repeat_button.js
+++ b/ui/file_manager/audio_player/elements/repeat_button.js
@@ -7,7 +7,15 @@
  *
  * This is for repeat button in Control Panel for Audio Player.
  */
+import 'chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_toggle_ripple.m.js';
+
+import {IronButtonState} from 'chrome://resources/polymer/v3_0/iron-behaviors/iron-button-state.js';
+import {IronControlState} from 'chrome://resources/polymer/v3_0/iron-behaviors/iron-control-state.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
 Polymer({
+  _template: html`{__html_template__}`,
+
   is: 'repeat-button',
 
   hostAttributes: {
@@ -16,8 +24,8 @@
   },
 
   behaviors: [
-    Polymer.IronButtonState,
-    Polymer.IronControlState,
+    IronButtonState,
+    IronControlState,
   ],
 
   properties: {
@@ -72,7 +80,7 @@
       return;
     }
 
-    var nextIndex = (this.index_ + 1) % this.modeName_.length;
+    const nextIndex = (this.index_ + 1) % this.modeName_.length;
     this.repeatMode = this.modeName_[nextIndex];
     this.index_ = nextIndex;
   },
diff --git a/ui/file_manager/audio_player/elements/track_list.html b/ui/file_manager/audio_player/elements/track_list.html
index 7dad4c3e..057ac8d 100644
--- a/ui/file_manager/audio_player/elements/track_list.html
+++ b/ui/file_manager/audio_player/elements/track_list.html
@@ -1,117 +1,104 @@
-<!--
-  -- Copyright 2015 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.
-  -->
 
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
+<style>
+  :host {
+    align-items: center;
+    background: rgb(245, 245, 245);
+    color: rgb(51, 51, 51);
+    cursor: default;
+    display: flex;
+    flex-direction: column;
+    font-size: 10pt;
+    justify-content: flex-start;
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
 
-<dom-module id="track-list">
-  <template>
-    <style>
-      :host {
-        align-items: center;
-        background: rgb(245, 245, 245);
-        color: rgb(51, 51, 51);
-        cursor: default;
-        display: flex;
-        flex-direction: column;
-        font-size: 10pt;
-        justify-content: flex-start;
-        overflow-x: hidden;
-        overflow-y: auto;
-      }
+  /* Track item. */
+  .track {
+    align-items: center;
+    display: flex;
+    flex: 0 0 auto;
+    flex-direction: row;
+    height: 48px;
+    justify-content: flex-start;
+    position: relative;
+    width: 100%;
+  }
 
-      /* Track item. */
-      .track {
-        align-items: center;
-        display: flex;
-        flex: 0 0 auto;
-        flex-direction: row;
-        height: 48px;
-        justify-content: flex-start;
-        position: relative;
-        width: 100%;
-      }
+  :host([expanded]) > .track:hover {
+    background-color: rgba(0, 0, 0, 0.08);
+  }
 
-      :host([expanded]) > .track:hover {
-        background-color: rgba(0, 0, 0, 0.08);
-      }
+  /* Track icon. */
+  .track .icon {
+    background-position: center;
+    background-repeat: no-repeat;
+    flex: none;
+    height: 32px;
+    margin: 8px;
+    pointer-events: none;
+    width: 32px;
+  }
 
-      /* Track icon. */
-      .track .icon {
-        background-position: center;
-        background-repeat: no-repeat;
-        flex: none;
-        height: 32px;
-        margin: 8px;
-        pointer-events: none;
-        width: 32px;
-      }
+  .track:hover .icon {
+    background-image: -webkit-image-set(
+        url(../assets/100/playlist_play.png) 1x,
+        url(../assets/200/playlist_play.png) 2x);
+    pointer-events: auto;
+  }
 
-      .track:hover .icon {
-        background-image: -webkit-image-set(
-            url(../assets/100/playlist_play.png) 1x,
-            url(../assets/200/playlist_play.png) 2x);
-        pointer-events: auto;
-      }
+  .track[active] .icon {
+    background-image: -webkit-image-set(
+        url(../assets/100/playlist_now_playing.png) 1x,
+        url(../assets/200/playlist_now_playing.png) 2x);
+  }
 
-      .track[active] .icon {
-        background-image: -webkit-image-set(
-            url(../assets/100/playlist_now_playing.png) 1x,
-            url(../assets/200/playlist_now_playing.png) 2x);
-      }
+  /* Track data. */
 
-      /* Track data. */
+  .track .data {
+    display: flex;
+    flex: 1 1 auto;
+    flex-direction: column;
+    justify-content: center;
+    margin-left: 0;
+    margin-right: 4px;
+    min-width: 0;
+  }
 
-      .track .data {
-        display: flex;
-        flex: 1 1 auto;
-        flex-direction: column;
-        justify-content: center;
-        margin-left: 0;
-        margin-right: 4px;
-        min-width: 0;
-      }
+  .track .data .data-title,
+  .track .data .data-artist {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
 
-      .track .data .data-title,
-      .track .data .data-artist {
-        overflow: hidden;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
+  .track .data .data-title {
+    color: rgb(51, 51, 51);
+    font-size: 13px;
+    font-weight: 500;
+  }
 
-      .track .data .data-title {
-        color: rgb(51, 51, 51);
-        font-size: 13px;
-        font-weight: 500;
-      }
+  .track .data .data-artist {
+    color: rgb(100, 100, 100);
+    font-size: 12px;
+  }
 
-      .track .data .data-artist {
-        color: rgb(100, 100, 100);
-        font-size: 12px;
-      }
-
-      paper-ripple {
-        bottom: 0;
-        color: rgb(51, 51, 51);
-        left: 0;
-        position: absolute;
-        right: 0;
-        top: 0;
-      }
-    </style>
-    <template is="dom-repeat" id="tracks" items="[[tracks]]">
-      <div class="track" active$="[[item.active]]" index$="[[index]]" on-click="trackClicked">
-        <div class="icon"></div>
-        <div class="data">
-          <div class="data-title">[[item.title]]</div>
-          <div class="data-artist">[[item.artist]]</div>
-        </div>
-        <paper-ripple initial-opacity="0.08"></paper-ripple>
-      </div>
-    </template>
-  </template>
-  <script src="track_list.js"></script>
-</dom-module>
+  paper-ripple {
+    bottom: 0;
+    color: rgb(51, 51, 51);
+    left: 0;
+    position: absolute;
+    right: 0;
+    top: 0;
+  }
+</style>
+<template is="dom-repeat" id="tracks" items="[[tracks]]">
+  <div class="track" active$="[[item.active]]" index$="[[index]]" on-click="trackClicked">
+    <div class="icon"></div>
+    <div class="data">
+      <div class="data-title">[[item.title]]</div>
+      <div class="data-artist">[[item.artist]]</div>
+    </div>
+    <paper-ripple initial-opacity="0.08"></paper-ripple>
+  </div>
+</template>
diff --git a/ui/file_manager/audio_player/elements/track_list.js b/ui/file_manager/audio_player/elements/track_list.js
index d8a286c..f3b62432 100644
--- a/ui/file_manager/audio_player/elements/track_list.js
+++ b/ui/file_manager/audio_player/elements/track_list.js
@@ -2,6 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import {Polymer, html} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import 'chrome://resources/polymer/v3_0/paper-ripple/paper-ripple.js';
+
+
 /**
  * @typedef {?{
  *   url: string,
@@ -11,12 +15,11 @@
  *   active: boolean
  * }}
  */
-/* #export */ let TrackInfo;
-
-(function() {
-/* #ignore */ 'use strict';
+export let TrackInfo;
 
 Polymer({
+  _template: html`{__html_template__}`,
+
   is: 'track-list',
 
   properties: {
@@ -297,4 +300,3 @@
     return newTrackIndex;
   },
 });
-})();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/js/BUILD.gn b/ui/file_manager/audio_player/js/BUILD.gn
index 6e9b80d..6275199 100644
--- a/ui/file_manager/audio_player/js/BUILD.gn
+++ b/ui/file_manager/audio_player/js/BUILD.gn
@@ -10,22 +10,10 @@
   testonly = true
   deps = [
     ":closure_compile_jsmodules",
-    ":closure_compile_legacy",
     ":closure_compile_polymer",
   ]
 }
 
-js_type_check("closure_compile_legacy") {
-  uses_legacy_modules = true
-  deps = [
-    ":audio_player",
-    ":background",
-    ":closure_compile_externs",
-    ":error_util",
-    ":metadata_worker",
-  ]
-}
-
 js_type_check("closure_compile_jsmodules") {
   deps = [
     ":background.m",
@@ -76,7 +64,7 @@
       [ "$root_gen_dir/ui/file_manager/audio_player/js/audio_player.m.js" ]
   deps = [
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/file_manager/audio_player/elements:audio_player.m",
+    "//ui/file_manager/audio_player/elements:audio_player",
     "//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",
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index dac13979..58e0007 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // clang-format off
-// #import '../elements/audio_player.m.js';
+// #import '../elements/audio_player.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 '../../file_manager/common/js/filtered_volume_manager.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
deleted file mode 100644
index 626138bf..0000000
--- a/ui/file_manager/audio_player/js/audio_player_scripts.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 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 src="../../../webui/resources/js/cr.js">
-// <include src="../../../webui/resources/js/cr/event_target.js">
-// <include src="../../../webui/resources/js/cr/ui/array_data_model.js">
-
-// Hack for polymer, notifying that CSP is enabled here.
-// TODO(yoshiki): Find a way to remove the hack.
-if (!('securityPolicy' in document)) {
-  document['securityPolicy'] = {};
-}
-if (!('allowsEval' in document.securityPolicy)) {
-  document.securityPolicy['allowsEval'] = false;
-}
-
-(function() {
-
-// 'strict mode' is invoked for this scope.
-'use strict';
-
-// Base classes.
-// <include src="../../file_manager/foreground/js/metadata/metadata_cache_set.js">
-// <include src="../../file_manager/foreground/js/metadata/metadata_provider.js">
-
-// <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="../../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">
-// <include src="../../file_manager/foreground/js/metadata/file_system_metadata_provider.js">
-// <include src="../../file_manager/foreground/js/metadata/metadata_cache_item.js">
-// <include src="../../file_manager/foreground/js/metadata/metadata_item.js">
-// <include src="../../file_manager/foreground/js/metadata/metadata_model.js">
-// <include src="../../file_manager/foreground/js/metadata/metadata_request.js">
-// <include src="../../file_manager/foreground/js/metadata/multi_metadata_provider.js">
-// <include src="../../file_manager/foreground/js/metadata/thumbnail_model.js">
-
-// <include src="audio_player.js">
-
-window.reload = reload;
-window.unload = unload;
-window.AudioPlayer = AudioPlayer;
-
-})();
diff --git a/ui/file_manager/audio_player/js/background_scripts.js b/ui/file_manager/audio_player/js/background_scripts.js
deleted file mode 100644
index b56a32c..0000000
--- a/ui/file_manager/audio_player/js/background_scripts.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// <include src="error_util.js">
-// <include src="test_util.js">
-// The main background script must be at the end.
-// <include src="background.js">
diff --git a/ui/file_manager/file_manager/BUILD.gn b/ui/file_manager/file_manager/BUILD.gn
index 88000807f..d2e3a59 100644
--- a/ui/file_manager/file_manager/BUILD.gn
+++ b/ui/file_manager/file_manager/BUILD.gn
@@ -43,7 +43,6 @@
 
   input_files = [
     # CSS:
-    "cws_widget/cws_widget_container.css",
     "foreground/css/combobutton.css",
     "foreground/css/common.css",
     "foreground/css/file_manager.css",
diff --git a/ui/file_manager/file_manager/background/js/test_util.js b/ui/file_manager/file_manager/background/js/test_util.js
index 848962d..d83dadf2 100644
--- a/ui/file_manager/file_manager/background/js/test_util.js
+++ b/ui/file_manager/file_manager/background/js/test_util.js
@@ -357,41 +357,6 @@
 };
 
 /**
- * Override the installWebstoreItem method in private api for test.
- *
- * @param {Window} contentWindow Window to be tested.
- * @param {string} expectedItemId Item ID to be called this method with.
- * @param {?string} intendedError Error message to be returned when the item id
- *     matches. 'null' represents no error.
- * @return {boolean} Always return true.
- */
-test.util.sync.overrideInstallWebstoreItemApi =
-    (contentWindow, expectedItemId, intendedError) => {
-      const setLastError = message => {
-        contentWindow.chrome.runtime.lastError =
-            message ? {message: message} : undefined;
-      };
-
-      const installWebstoreItem = (itemId, silentInstallation, callback) => {
-        setTimeout(() => {
-          if (itemId !== expectedItemId) {
-            setLastError('Invalid Chrome Web Store item ID');
-            callback();
-            return;
-          }
-
-          setLastError(intendedError);
-          callback();
-        }, 0);
-      };
-
-      test.util.executedTasks_ = [];
-      contentWindow.chrome.webstoreWidgetPrivate.installWebstoreItem =
-          installWebstoreItem;
-      return true;
-    };
-
-/**
  * Override the task-related methods in private api for test.
  *
  * @param {Window} contentWindow Window to be tested.
diff --git a/ui/file_manager/file_manager/cws_widget/BUILD.gn b/ui/file_manager/file_manager/cws_widget/BUILD.gn
deleted file mode 100644
index 53c334d5..0000000
--- a/ui/file_manager/file_manager/cws_widget/BUILD.gn
+++ /dev/null
@@ -1,134 +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("//ui/webui/resources/js/cr.gni")
-import("//ui/webui/resources/tools/js_modulizer.gni")
-
-group("closure_compile") {
-  testonly = true
-  deps = [
-    ":closure_compile_jsmodules",
-    ":closure_compile_module",
-  ]
-}
-
-js_type_check("closure_compile_jsmodules") {
-  deps = [
-    ":app_installer.m",
-    ":cws_webview_client.m",
-    ":cws_widget_container.m",
-    ":cws_widget_container_error_dialog.m",
-    ":cws_widget_container_platform_delegate.m",
-  ]
-}
-
-js_type_check("closure_compile_module") {
-  uses_legacy_modules = true
-  deps = [
-    ":app_installer",
-    ":cws_webview_client",
-    ":cws_widget_container",
-    ":cws_widget_container_error_dialog",
-    ":cws_widget_container_platform_delegate",
-  ]
-}
-
-js_library("app_installer") {
-  deps = [ ":cws_widget_container_platform_delegate" ]
-}
-
-js_library("app_installer.m") {
-  sources = [
-    "$root_gen_dir/ui/file_manager/file_manager/cws_widget/app_installer.m.js",
-  ]
-  deps = [ ":cws_widget_container_platform_delegate.m" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("cws_widget_container") {
-  deps = [
-    ":app_installer",
-    ":cws_webview_client",
-    ":cws_widget_container_error_dialog",
-  ]
-}
-
-js_library("cws_widget_container.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container.m.js" ]
-  deps = [
-    ":app_installer.m",
-    ":cws_webview_client.m",
-    ":cws_widget_container_error_dialog.m",
-    ":cws_widget_container_platform_delegate.m",
-    "//ui/webui/resources/js:assert.m",
-  ]
-  externs_list = [ "$externs_path/webview_tag.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("cws_widget_container_error_dialog") {
-  deps = [
-    "../common/js:util",
-    "//ui/webui/resources/js/cr/ui:dialogs",
-  ]
-}
-
-js_library("cws_widget_container_error_dialog.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container_error_dialog.m.js" ]
-
-  deps = [
-    "../common/js:util.m",
-    "//ui/webui/resources/js/cr/ui:dialogs.m",
-  ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("cws_widget_container_platform_delegate") {
-}
-
-js_library("cws_widget_container_platform_delegate.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_widget_container_platform_delegate.m.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_library("cws_webview_client") {
-  deps = [
-    ":cws_widget_container_platform_delegate",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js/cr:event_target",
-  ]
-  externs_list = [
-    "$externs_path/chrome_extensions.js",
-    "$externs_path/webview_tag.js",
-  ]
-}
-
-js_library("cws_webview_client.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/file_manager/cws_widget/cws_webview_client.m.js" ]
-  deps = [
-    ":cws_widget_container_platform_delegate.m",
-    "//ui/webui/resources/js:cr.m",
-    "//ui/webui/resources/js/cr:event_target.m",
-  ]
-  externs_list = [ "$externs_path/webview_tag.js" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
-js_modulizer("modulize") {
-  input_files = [
-    "cws_widget_container_error_dialog.js",
-    "cws_widget_container.js",
-    "cws_webview_client.js",
-    "app_installer.js",
-    "cws_widget_container_platform_delegate.js",
-  ]
-
-  namespace_rewrites = cr_namespace_rewrites
-}
diff --git a/ui/file_manager/file_manager/cws_widget/app_installer.js b/ui/file_manager/file_manager/cws_widget/app_installer.js
deleted file mode 100644
index 3cda7617..0000000
--- a/ui/file_manager/file_manager/cws_widget/app_installer.js
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2013 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.
-
-// clang-format off
-// #import {CWSWidgetContainerPlatformDelegate} from './cws_widget_container_platform_delegate.m.js';
-// clang-format on
-
-/**
- * Manage the installation of apps.
- */
-/* #export */ class AppInstaller {
-  /**
-   * @param {string} itemId Item id to be installed.
-   * @param {!CWSWidgetContainerPlatformDelegate} delegate Delegate for
-   *     accessing Chrome platform APIs.
-   */
-  constructor(itemId, delegate) {
-    /** @private {!CWSWidgetContainerPlatformDelegate} */
-    this.delegate_ = delegate;
-    this.itemId_ = itemId;
-    this.callback_ = null;
-  }
-
-  /**
-   * Start an installation.
-   * @param {function(AppInstaller.Result, string)} callback Called when the
-   *     installation is finished.
-   */
-  install(callback) {
-    this.callback_ = callback;
-    this.delegate_.installWebstoreItem(
-        this.itemId_, this.onInstallCompleted_.bind(this));
-  }
-
-  /**
-   * Prevents {@code this.callback_} from being called.
-   */
-  cancel() {
-    // TODO(tbarzic): Would it make sense to uninstall the app on success if the
-    // app instaler is cancelled instead of just invalidating the callback?
-    this.callback_ = null;
-  }
-
-  /**
-   * Called when the installation is completed.
-   *
-   * @param {?string} error Null if the installation is success,
-   *     otherwise error message.
-   * @private
-   */
-  onInstallCompleted_(error) {
-    if (!this.callback_) {
-      return;
-    }
-
-    let installerResult = AppInstaller.Result.SUCCESS;
-    if (error !== null) {
-      installerResult = error == AppInstaller.USER_CANCELLED_ERROR_STR_ ?
-          AppInstaller.Result.CANCELLED :
-          AppInstaller.Result.ERROR;
-    }
-    this.callback_(installerResult, error || '');
-    this.callback_ = null;
-  }
-}
-
-/**
- * Type of result.
- *
- * @enum {string}
- * @const
- */
-AppInstaller.Result = {
-  SUCCESS: 'AppInstaller.success',
-  CANCELLED: 'AppInstaller.cancelled',
-  ERROR: 'AppInstaller.error'
-};
-Object.freeze(AppInstaller.Result);
-
-/**
- * Error message for user cancellation. This must be match with the constant
- * 'kUserCancelledError' in C/B/extensions/webstore_standalone_installer.cc.
- * @type {string}
- * @const
- * @private
- */
-AppInstaller.USER_CANCELLED_ERROR_STR_ = 'User cancelled install';
diff --git a/ui/file_manager/file_manager/cws_widget/cws_webview_client.js b/ui/file_manager/file_manager/cws_widget/cws_webview_client.js
deleted file mode 100644
index 2d8231a..0000000
--- a/ui/file_manager/file_manager/cws_widget/cws_webview_client.js
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright 2013 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.
-
-// clang-format off
-// #import {CWSWidgetContainerPlatformDelegate} from './cws_widget_container_platform_delegate.m.js';
-// #import {NativeEventTarget as EventTarget} from 'chrome://resources/js/cr/event_target.m.js';
-// #import {dispatchSimpleEvent} from 'chrome://resources/js/cr.m.js';
-// clang-format on
-
-/* #export */ class CWSContainerClient extends cr.EventTarget {
-  /**
-   * @param {WebView} webView Web View tag.
-   * @param {number} width Width of the CWS widget.
-   * @param {number} height Height of the CWS widget.
-   * @param {string} url Share Url for an entry.
-   * @param {string} target Target (scheme + host + port) of the widget.
-   * @param {Object<*>} options Options to be sent to the dialog host.
-   * @param {!CWSWidgetContainerPlatformDelegate} delegate Delegate for
-   *     accessing Chrome platform APIs.
-   */
-  constructor(webView, width, height, url, target, options, delegate) {
-    super();
-
-    /** @private {!CWSWidgetContainerPlatformDelegate} */
-    this.delegate_ = delegate;
-    this.webView_ = webView;
-    this.width_ = width;
-    this.height_ = height;
-    this.url_ = url;
-    this.target_ = target;
-    this.options_ = options;
-
-    this.loaded_ = false;
-    this.loading_ = false;
-
-    this.onMessageBound_ = this.onMessage_.bind(this);
-    this.onLoadStopBound_ = this.onLoadStop_.bind(this);
-    this.onLoadAbortBound_ = this.onLoadAbort_.bind(this);
-  }
-
-  /**
-   * Handles messages from the widget
-   * @param {Event} event Message event.
-   * @private
-   */
-  onMessage_(event) {
-    if (event.origin != this.target_) {
-      return;
-    }
-
-    const data = event.data;
-    switch (data['message']) {
-      case 'widget_loaded':
-        this.onWidgetLoaded_();
-        break;
-      case 'widget_load_failed':
-        this.onWidgetLoadFailed_();
-        break;
-      case 'before_install':
-        this.sendInstallRequest_(data['item_id']);
-        break;
-      case 'after_install':
-        this.sendInstallDone_(data['item_id']);
-        break;
-      default:
-        console.error('Unexpected message: ' + data['message'], data);
-    }
-  }
-
-  /**
-   * Called when receiving 'loadstop' event from the <webview>.
-   * @param {Event} event Message event.
-   * @private
-   */
-  onLoadStop_(event) {
-    if (this.url_ == this.webView_.src && !this.loaded_) {
-      this.loaded_ = true;
-      this.postInitializeMessage_();
-    }
-  }
-
-  /**
-   * Called when the widget is loaded successfully.
-   * @private
-   */
-  onWidgetLoaded_() {
-    cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOADED);
-  }
-
-  /**
-   * Called when the widget is failed to load.
-   * @private
-   */
-  onWidgetLoadFailed_() {
-    this.sendWidgetLoadFailed_();
-  }
-
-  /**
-   * Called when receiving the 'loadabort' event from <webview>.
-   * @param {Event} event Message event.
-   * @private
-   */
-  onLoadAbort_(event) {
-    this.sendWidgetLoadFailed_();
-  }
-
-  /**
-   * Called when the installation is completed from the suggest-app dialog.
-   *
-   * @param {boolean} result True if the installation is success, false if
-   *     failed.
-   * @param {string} itemId Item id to be installed.
-   */
-  onInstallCompleted(result, itemId) {
-    if (result) {
-      this.postInstallSuccessMessage_(itemId);
-    } else {
-      this.postInstallFailureMessage_(itemId);
-    }
-  }
-
-  /**
-   * Send the fail message to the suggest-app dialog.
-   * @private
-   */
-  sendWidgetLoadFailed_() {
-    cr.dispatchSimpleEvent(this, CWSContainerClient.Events.LOAD_FAILED);
-  }
-
-  /**
-   * Send the install request to the suggest-app dialog.
-   *
-   * @param {string} itemId Item id to be installed.
-   * @private
-   */
-  sendInstallRequest_(itemId) {
-    const event = new Event(CWSContainerClient.Events.REQUEST_INSTALL);
-    event.itemId = itemId;
-    this.dispatchEvent(event);
-  }
-
-  /**
-   * Notifies the suggest-app dialog that the item installation is completed.
-   *
-   * @param {string} itemId The installed item ID.
-   * @private
-   */
-  sendInstallDone_(itemId) {
-    const event = new Event(CWSContainerClient.Events.INSTALL_DONE);
-    event.itemId = itemId;
-    this.dispatchEvent(event);
-  }
-
-  /**
-   * Send the 'install_failure' message to the widget.
-   *
-   * @param {string} itemId Item id to be installed.
-   * @private
-   */
-  postInstallFailureMessage_(itemId) {
-    const message = {message: 'install_failure', item_id: itemId, v: 1};
-
-    this.postMessage_(message);
-  }
-
-  /**
-   * Send the 'install_success' message to the widget.
-   *
-   * @param {string} itemId Item id to be installed.
-   * @private
-   */
-  postInstallSuccessMessage_(itemId) {
-    const message = {message: 'install_success', item_id: itemId, v: 1};
-
-    this.postMessage_(message);
-  }
-
-  /**
-   * Send the 'initialize' message to the widget.
-   * @private
-   */
-  postInitializeMessage_() {
-    new Promise((fulfill, reject) => {
-      this.delegate_.getInstalledItems(
-          /**
-           * @param {?Array<!string>} items Installed items.
-           *     Null on error.
-           */
-          items => {
-            if (!items) {
-              reject('Failed to retrive installed items.');
-              return;
-            }
-            fulfill(items);
-          });
-    })
-        .then(/**
-               * @param {!Array<string>} preinstalledExtensionIDs
-               */
-              preinstalledExtensionIDs => {
-                const message = {
-                  message: 'initialize',
-                  hl: this.delegate_.strings.UI_LOCALE,
-                  width: this.width_,
-                  height: this.height_,
-                  preinstalled_items: preinstalledExtensionIDs,
-                  v: 1
-                };
-
-                if (this.options_) {
-                  Object.keys(this.options_).forEach(key => {
-                    message[key] = this.options_[key];
-                  });
-                }
-
-                this.postMessage_(message);
-              });
-  }
-
-  /**
-   * Send a message to the widget. This method shouldn't be called directly,
-   * should from more specified posting function (eg. postXyzMessage_()).
-   *
-   * @param {Object} message Message object to be posted.
-   * @private
-   */
-  postMessage_(message) {
-    if (!this.webView_.contentWindow) {
-      return;
-    }
-
-    this.webView_.contentWindow.postMessage(message, this.target_);
-  }
-
-  /**
-   * Loads the page to <webview>. Can be called only once.
-   */
-  load() {
-    if (this.loading_ || this.loaded_) {
-      throw new Error('Already loaded.');
-    }
-    this.loading_ = true;
-    this.loaded_ = false;
-
-    window.addEventListener('message', this.onMessageBound_);
-    this.webView_.addEventListener('loadstop', this.onLoadStopBound_);
-    this.webView_.addEventListener('loadabort', this.onLoadAbortBound_);
-    this.webView_.setAttribute('src', this.url_);
-  }
-
-  /**
-   * Aborts loading of the embedded dialog and performs cleanup.
-   */
-  abort() {
-    window.removeEventListener('message', this.onMessageBound_);
-    this.webView_.removeEventListener('loadstop', this.onLoadStopBound_);
-    this.webView_.removeEventListener('loadabort', this.onLoadAbortBound_);
-    this.webView_.stop();
-  }
-
-  /**
-   * Cleans the dialog by removing all handlers.
-   */
-  dispose() {
-    this.abort();
-  }
-}
-
-/**
- * Events CWSContainerClient fires
- *
- * @enum {string}
- * @const
- */
-CWSContainerClient.Events = {
-  LOADED: 'CWSContainerClient.Events.LOADED',
-  LOAD_FAILED: 'CWSContainerClient.Events.LOAD_FAILED',
-  REQUEST_INSTALL: 'CWSContainerClient.Events.REQUEST_INSTALL',
-  INSTALL_DONE: 'CWSContainerClient.Events.INSTALL_DONE'
-};
-Object.freeze(CWSContainerClient.Events);
diff --git a/ui/file_manager/file_manager/cws_widget/cws_widget_container.css b/ui/file_manager/file_manager/cws_widget/cws_widget_container.css
deleted file mode 100644
index f707ac1..0000000
--- a/ui/file_manager/file_manager/cws_widget/cws_widget_container.css
+++ /dev/null
@@ -1,121 +0,0 @@
-/* Copyright 2015 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. */
-
-.cws-widget-container-root {
-  position: relative;
-}
-
-.cws-widget-webview-container {
-  border-bottom: solid 1px #bbb;
-  border-top: solid 1px #bbb;
-  position: relative;
-}
-
-.cws-widget-webview-container webview {
-  outline: none;
-}
-
-.cws-widget-spinner-layer {
-  background: url(chrome://resources/images/throbber_medium.svg) center/32px
-      no-repeat;
-  background-color: rgba(255, 255, 255, 0.7);
-  bottom: 0;
-  left: 0;
-  outline: none;
-  position: absolute;
-  right: 0;
-  top: 0;
-  transition: opacity 500ms;
-  z-index: 525;
-}
-
-.cws-widget-spinner-layer:not(.cws-widget-show-spinner) {
-  background: none;
-  opacity: 0;
-  pointer-events: none;
-}
-
-.cws-widget-spinner-layer.cws-widget-hiding-spinner {
-  /* Transition end event would not fire if opacity was set to 0. */
-  opacity: 0.01;
-}
-
-.cws-widget-buttons {
-  background: #eee;
-  width: 100%;
-}
-
-body.files-ng .cws-widget-buttons {
-  align-items: center;
-  background: var(--cros-bg-color);
-  display: flex;
-  /* subtract the bottom padding from the container outside */
-  height: calc(64px - 20px);
-  margin-top: 16px;
-}
-
-.cws-widget-webstore-button {
-  color: rgb(0, 0, 255);
-  cursor: pointer;
-  display: flex;
-  height: 16px;
-  padding-bottom: 10px;
-  padding-inline-end: 10px;
-  padding-inline-start: 12px;
-  padding-top: 10px;
-}
-
-body.files-ng .cws-widget-webstore-button {
-  color: var(--cros-button-background-color-primary);
-  height: 24px;
-  padding-inline-start: 0;
-}
-
-.cws-widget-webstore-button-icon {
-  background-image: -webkit-image-set(
-    url(chrome://theme/IDR_WEBSTORE_ICON_16) 1x,
-    url(chrome://theme/IDR_WEBSTORE_ICON_16@2x) 2x);
-  background-repeat: no-repeat;
-  display: inline-block;
-  height: 16px;
-  margin-inline-end: 8px;
-  width: 16px;
-}
-
-body.files-ng .cws-widget-webstore-button-icon {
-  background-position: center;
-  height: 24px;
-  width: 24px;
-}
-
-.cws-widget-webstore-button-label {
-  flex: 1;
-  line-height: 16px;
-}
-
-body.files-ng .cws-widget-webstore-button-label {
-  line-height: 24px;
-}
-
-.cr-dialog-frame.cws-widget-error-dialog-frame {
-  width: 300px;
-}
-
-.cws-widget-error-dialog-frame .cws-widget-error-dialog-img {
-  background-image: -webkit-image-set(
-    url(chrome://theme/IDR_ERROR_NETWORK_GENERIC) 1x,
-    url(chrome://theme/IDR_ERROR_NETWORK_GENERIC@2x) 2x);
-  background-position: center top;
-  background-repeat: no-repeat;
-  height: 100px;
-  margin-inline-start: 35px;
-}
-
-:root[dir=rtl] .cws-widget-error-dialog-frame .cws-widget-error-dialog-img {
-  margin-inline-start: -35px;
-}
-
-.cws-widget-error-dialog-text {
-  text-align: center;
-}
diff --git a/ui/file_manager/file_manager/cws_widget/cws_widget_container.js b/ui/file_manager/file_manager/cws_widget/cws_widget_container.js
deleted file mode 100644
index 005841c..0000000
--- a/ui/file_manager/file_manager/cws_widget/cws_widget_container.js
+++ /dev/null
@@ -1,961 +0,0 @@
-// Copyright 2015 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 CWSWidgetContainer contains a Chrome Web Store widget that
- * displays list of apps that satisfy certain constraints (e.g. fileHandler apps
- * that can handle files with specific file extension or MIME type) and enables
- * the user to install apps directly from it. CWSWidgetContainer implements
- * client side of the widget, which handles widget loading and app installation.
- */
-
-// clang-format off
-// #import {CWSWidgetContainerMetricsImpl, CWSWidgetContainerPlatformDelegate} from './cws_widget_container_platform_delegate.m.js';
-// #import {AppInstaller} from './app_installer.m.js';
-// #import {CWSContainerClient} from './cws_webview_client.m.js';
-// #import {CWSWidgetContainerErrorDialog} from './cws_widget_container_error_dialog.m.js';
-// #import {assert} from 'chrome://resources/js/assert.m.js';
-// clang-format on
-
-/**
- * The width of the widget (in pixels)
- * @type {number}
- * @const
- */
-const WEBVIEW_WIDTH = 735;
-
-/**
- * The height of the widget (in pixels).
- * @type {number}
- * @const
- */
-const WEBVIEW_HEIGHT = 480;
-
-/**
- * The URL of the widget showing suggested apps.
- * @type {string}
- * @const
- */
-const CWS_WIDGET_URL =
-    'https://clients5.google.com/webstore/wall/cros-widget-container';
-
-/**
- * The origin of the widget.
- * @type {string}
- * @const
- */
-const CWS_WIDGET_ORIGIN = 'https://clients5.google.com';
-
-/**
- * Creates the widget container element in DOM tree.
- */
-/* #export */ class CWSWidgetContainer {
-  /**
-   *
-   * @param {!HTMLDocument} document The document to contain this container.
-   * @param {!HTMLElement} parentNode Node to be parent for this container.
-   * @param {!CWSWidgetContainerPlatformDelegate} delegate Delegate for
-   *     accessing Chrome platform APIs.
-   * @param {!{
-   *   overrideCwsContainerUrlForTest: (string|undefined),
-   *   overrideCwsContainerOriginForTest: (string|undefined)
-   * }} params Overrides for container params.
-   */
-  constructor(document, parentNode, delegate, params) {
-    /** @private {!CWSWidgetContainerPlatformDelegate} */
-    this.delegate_ = delegate;
-
-    /** @private {!CWSWidgetContainer.MetricsRecorder} */
-    this.metricsRecorder_ =
-        new CWSWidgetContainer.MetricsRecorder(delegate.metricsImpl);
-
-    /**
-     * The document that will contain the container.
-     * @const {!HTMLDocument}
-     * @private
-     */
-    this.document_ = document;
-
-    /**
-     * The element containing the widget webview.
-     * @type {!Element}
-     * @private
-     */
-    this.webviewContainer_ = document.createElement('div');
-    this.webviewContainer_.classList.add('cws-widget-webview-container');
-    this.webviewContainer_.style.width = WEBVIEW_WIDTH + 'px';
-    this.webviewContainer_.style.height = WEBVIEW_HEIGHT + 'px';
-    parentNode.appendChild(this.webviewContainer_);
-
-    parentNode.classList.add('cws-widget-container-root');
-
-    /**
-     * Element showing spinner layout in place of Web Store widget.
-     * @type {!Element}
-     */
-    const spinnerLayer = document.createElement('div');
-    spinnerLayer.className = 'cws-widget-spinner-layer';
-    parentNode.appendChild(spinnerLayer);
-
-    /** @private {!CWSWidgetContainer.SpinnerLayerController} */
-    this.spinnerLayerController_ =
-        new CWSWidgetContainer.SpinnerLayerController(spinnerLayer);
-
-    /**
-     * The widget container's button strip.
-     * @type {!Element}
-     */
-    const buttons = document.createElement('div');
-    buttons.classList.add('cws-widget-buttons');
-    parentNode.appendChild(buttons);
-
-    /**
-     * Button that opens the Webstore URL.
-     * @const {!Element}
-     * @private
-     */
-    this.webstoreButton_ = document.createElement('div');
-    this.webstoreButton_.hidden = true;
-    this.webstoreButton_.setAttribute('role', 'button');
-    this.webstoreButton_.classList.add('button2');
-    this.webstoreButton_.tabIndex = 0;
-
-    /**
-     * Icon for the Webstore button.
-     * @type {!Element}
-     */
-    const webstoreButtonIcon = this.document_.createElement('span');
-    webstoreButtonIcon.classList.add('cws-widget-webstore-button-icon');
-    this.webstoreButton_.appendChild(webstoreButtonIcon);
-
-    /**
-     * The label for the Webstore button.
-     * @type {!Element}
-     */
-    const webstoreButtonLabel = this.document_.createElement('span');
-    webstoreButtonLabel.classList.add('cws-widget-webstore-button-label');
-    webstoreButtonLabel.textContent = this.delegate_.strings.LINK_TO_WEBSTORE;
-    this.webstoreButton_.appendChild(webstoreButtonLabel);
-
-    this.webstoreButton_.addEventListener(
-        'click', this.onWebstoreLinkActivated_.bind(this));
-    this.webstoreButton_.addEventListener(
-        'keydown', this.onWebstoreLinkKeyDown_.bind(this));
-
-    buttons.appendChild(this.webstoreButton_);
-
-    /**
-     * The webview element containing the Chrome Web Store widget.
-     * @type {?WebView}
-     * @private
-     */
-    this.webview_ = null;
-
-    /**
-     * The Chrome Web Store widget URL.
-     * @const {string}
-     * @private
-     */
-    this.widgetUrl_ = params.overrideCwsContainerUrlForTest || CWS_WIDGET_URL;
-
-    /**
-     * The Chrome Web Store widget origin.
-     * @const {string}
-     * @private
-     */
-    this.widgetOrigin_ =
-        params.overrideCwsContainerOriginForTest || CWS_WIDGET_ORIGIN;
-
-    /**
-     * Map of options for the widget.
-     * @type {?Object<*>}
-     * @private
-     */
-    this.options_ = null;
-
-    /**
-     * The ID of the item being installed. Null if no items are being installed.
-     * @type {?string}
-     * @private
-     */
-    this.installingItemId_ = null;
-
-    /**
-     * The ID of the the installed item. Null if no item was installed.
-     * @type {?string}
-     * @private
-     */
-    this.installedItemId_ = null;
-
-    /**
-     * The current widget state.
-     * @type {CWSWidgetContainer.State}
-     * @private
-     */
-    this.state_ = CWSWidgetContainer.State.UNINITIALIZED;
-
-    /**
-     * The Chrome Web Store access token to be used when communicating with the
-     * Chrome Web Store widget.
-     * @type {?string}
-     * @private
-     */
-    this.accessToken_ = null;
-
-    /**
-     * Called when the Chrome Web Store widget is done. It resolves the promise
-     * returned by {@code this.start()}.
-     * @type {?function(CWSWidgetContainer.ResolveReason)}
-     * @private
-     */
-    this.resolveStart_ = null;
-
-    /**
-     * Promise for retrieving {@code this.accessToken_}.
-     * @type {Promise<string>}
-     * @private
-     */
-    this.tokenGetter_ = this.createTokenGetter_();
-
-    /**
-     * Dialog to be shown when an installation attempt fails.
-     * @type {CWSWidgetContainerErrorDialog}
-     * @private
-     */
-    this.errorDialog_ = new CWSWidgetContainerErrorDialog(parentNode);
-
-    /** @private {?AppInstaller} */
-    this.appInstaller_ = null;
-
-    /** @private {?CWSContainerClient} */
-    this.webviewClient_ = null;
-
-    /** @private {?string} */
-    this.webStoreUrl_ = null;
-  }
-
-  /**
-   * @return {!Element} The element that should be focused initially.
-   */
-  getInitiallyFocusedElement() {
-    return this.webviewContainer_;
-  }
-
-  /**
-   * Injects headers into the passed request.
-   *
-   * @param {!Object} e Request event.
-   * @return {!BlockingResponse} Modified headers.
-   * @private
-   */
-  authorizeRequest_(e) {
-    e.requestHeaders.push(
-        {name: 'Authorization', value: 'Bearer ' + this.accessToken_});
-    return /** @type {!BlockingResponse}*/ ({requestHeaders: e.requestHeaders});
-  }
-
-  /**
-   * Retrieves the authorize token.
-   * @return {Promise<string>} The promise with the retrieved access token.
-   * @private
-   */
-  createTokenGetter_() {
-    return new Promise((resolve, reject) => {
-      if (window.IN_TEST) {
-        // In test, use a dummy string as token. This must be a non-empty
-        // string.
-        resolve('DUMMY_ACCESS_TOKEN_FOR_TEST');
-        return;
-      }
-
-      // Fetch or update the access token.
-      this.delegate_.requestWebstoreAccessToken(
-          /**
-             @param {?string} accessToken The requested token. Null on error.
-               */
-          accessToken => {
-            if (!accessToken) {
-              reject('Error retrieving Web Store access token.');
-              return;
-            }
-            resolve(accessToken);
-          });
-    });
-  }
-
-  /**
-   * @return {boolean} Whether the container is in initial state, i.e. inactive.
-   */
-  isInInitialState() {
-    return this.state_ === CWSWidgetContainer.State.UNINITIALIZED;
-  }
-
-  /**
-   * Ensures that the widget container is in the state where it can properly
-   * handle showing the Chrome Web Store webview.
-   * @return {Promise} Resolved when the container is ready to be used.
-   */
-  ready() {
-    return new Promise((resolve, reject) => {
-      if (this.state_ !== CWSWidgetContainer.State.UNINITIALIZED) {
-        reject('Invalid state.');
-        return;
-      }
-
-      this.spinnerLayerController_.setAltText(
-          this.delegate_.strings.LOADING_SPINNER_ALT);
-      this.spinnerLayerController_.setVisible(true);
-
-      this.metricsRecorder_.recordShowDialog();
-      this.metricsRecorder_.startLoad();
-
-      this.state_ = CWSWidgetContainer.State.GETTING_ACCESS_TOKEN;
-
-      this.tokenGetter_.then(
-          accessToken => {
-            this.state_ = CWSWidgetContainer.State.ACCESS_TOKEN_READY;
-            this.accessToken_ = accessToken;
-            resolve();
-          },
-          error => {
-            this.spinnerLayerController_.setVisible(false);
-            this.state_ = CWSWidgetContainer.State.UNINITIALIZED;
-            reject('Failed to get Web Store access token: ' + error);
-          });
-    });
-  }
-
-  /**
-   * Initializes and starts loading the Chrome Web Store widget webview.
-   * Must not be called before {@code this.ready()} is resolved.
-   *
-   * @param {!Object<*>} options Map of options for the dialog.
-   * @param {?string} webStoreUrl Url for more results. Null if not supported.
-   * @return {!Promise<CWSWidgetContainer.ResolveReason>} Resolved when app
-   *     installation is done, or the installation is cancelled.
-   */
-  start(options, webStoreUrl) {
-    return new Promise((resolve, reject) => {
-      if (this.state_ !== CWSWidgetContainer.State.ACCESS_TOKEN_READY) {
-        this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING;
-        reject('Invalid state in |start|.');
-        return;
-      }
-
-      if (!this.accessToken_) {
-        this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING;
-        reject('No access token.');
-        return;
-      }
-
-      this.resolveStart_ = resolve;
-
-      this.state_ = CWSWidgetContainer.State.INITIALIZING;
-
-      this.webStoreUrl_ = webStoreUrl;
-      this.options_ = options;
-
-      this.webstoreButton_.hidden = !webStoreUrl;
-      this.webstoreButton_.classList.toggle(
-          'cws-widget-webstore-button', !!webStoreUrl);
-
-      this.webview_ =
-          /** @type {!WebView} */ (this.document_.createElement('webview'));
-      this.webview_.id = 'cws-widget';
-      this.webview_.partition = 'persist:cwswidgets';
-      this.webview_.style.width = WEBVIEW_WIDTH + 'px';
-      this.webview_.style.height = WEBVIEW_HEIGHT + 'px';
-      this.webview_.request.onBeforeSendHeaders.addListener(
-          this.authorizeRequest_.bind(this),
-          /** @type {!RequestFilter}*/ ({urls: [this.widgetOrigin_ + '/*']}),
-          ['blocking', 'requestHeaders']);
-      this.webview_.addEventListener('newwindow', event => {
-        event = /** @type {NewWindowEvent} */ (event);
-        // Discard the window object and reopen in an external window.
-        event.window.discard();
-        window.open(event.targetUrl);
-        event.preventDefault();
-      });
-      this.webviewContainer_.appendChild(this.webview_);
-
-      this.spinnerLayerController_.setElementToFocusOnHide(this.webview_);
-      this.spinnerLayerController_.setAltText(
-          this.delegate_.strings.LOADING_SPINNER_ALT);
-      this.spinnerLayerController_.setVisible(true);
-
-      this.webviewClient_ = new CWSContainerClient(
-          this.webview_, WEBVIEW_WIDTH, WEBVIEW_HEIGHT, this.widgetUrl_,
-          this.widgetOrigin_, this.options_, this.delegate_);
-      this.webviewClient_.addEventListener(
-          CWSContainerClient.Events.LOADED, this.onWidgetLoaded_.bind(this));
-      this.webviewClient_.addEventListener(
-          CWSContainerClient.Events.LOAD_FAILED,
-          this.onWidgetLoadFailed_.bind(this));
-      this.webviewClient_.addEventListener(
-          CWSContainerClient.Events.REQUEST_INSTALL,
-          this.onInstallRequest_.bind(this));
-      this.webviewClient_.addEventListener(
-          CWSContainerClient.Events.INSTALL_DONE,
-          this.onInstallDone_.bind(this));
-      this.webviewClient_.load();
-    });
-  }
-
-  /**
-   * Called when the 'See more...' button is activated. It opens
-   * {@code this.webstoreUrl_}.
-   * @param {Event} e The event that activated the link. Either mouse click or
-   *     key down event.
-   * @private
-   */
-  onWebstoreLinkActivated_(e) {
-    if (!this.webStoreUrl_) {
-      return;
-    }
-    window.open(this.webStoreUrl_);
-    this.state_ = CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING;
-    this.reportDone_();
-  }
-
-  /**
-   * Key down event handler for webstore button element. If the key is enter, it
-   * activates the button.
-   * @param {Event} e The event
-   * @private
-   */
-  onWebstoreLinkKeyDown_(e) {
-    if (e.keyCode !== 13 /* Enter */) {
-      return;
-    }
-    this.onWebstoreLinkActivated_(e);
-  }
-
-  /**
-   * Called when the widget is loaded successfully.
-   * @param {Event} event Event.
-   * @private
-   */
-  onWidgetLoaded_(event) {
-    this.metricsRecorder_.finishLoad();
-    this.metricsRecorder_.recordLoad(
-        CWSWidgetContainer.MetricsRecorder.LOAD.SUCCEEDED);
-
-    this.state_ = CWSWidgetContainer.State.INITIALIZED;
-
-    this.spinnerLayerController_.setVisible(false);
-    this.webview_.focus();
-  }
-
-  /**
-   * Called when the widget is failed to load.
-   * @param {Event} event Event.
-   * @private
-   */
-  onWidgetLoadFailed_(event) {
-    this.metricsRecorder_.recordLoad(
-        CWSWidgetContainer.MetricsRecorder.LOAD.FAILED);
-
-    this.spinnerLayerController_.setVisible(false);
-    this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING;
-    this.reportDone_();
-  }
-
-  /**
-   * Called when the connection status is changed to offline.
-   */
-  onConnectionLost() {
-    if (this.state_ !== CWSWidgetContainer.State.UNINITIALIZED) {
-      this.state_ = CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING;
-      this.reportDone_();
-    }
-  }
-
-  /**
-   * Called when receiving the install request from the webview client.
-   * @param {Event} e Event.
-   * @private
-   */
-  onInstallRequest_(e) {
-    const itemId = e.itemId;
-    this.installingItemId_ = itemId;
-
-    this.appInstaller_ = new AppInstaller(itemId, this.delegate_);
-    this.appInstaller_.install(this.onItemInstalled_.bind(this));
-
-    this.spinnerLayerController_.setAltText(
-        this.delegate_.strings.INSTALLING_SPINNER_ALT);
-    this.spinnerLayerController_.setVisible(true);
-    this.state_ = CWSWidgetContainer.State.INSTALLING;
-  }
-
-  /**
-   * Called when the webview client receives install confirmation from the
-   * Web Store widget.
-   * @param {Event} e Event
-   * @private
-   */
-  onInstallDone_(e) {
-    this.spinnerLayerController_.setVisible(false);
-    this.state_ = CWSWidgetContainer.State.INSTALLED_CLOSING;
-    this.reportDone_();
-  }
-
-  /**
-   * Called when the installation is completed from the app installer.
-   * @param {AppInstaller.Result} result Result of the installation.
-   * @param {string} error Detail of the error.
-   * @private
-   */
-  onItemInstalled_(result, error) {
-    const success = (result === AppInstaller.Result.SUCCESS);
-
-    // If install succeeded, the spinner will be removed once
-    // |this.webviewClient_| dispatched INSTALL_DONE event.
-    if (!success) {
-      this.spinnerLayerController_.setVisible(false);
-    }
-
-    this.state_ = success ?
-        CWSWidgetContainer.State.WAITING_FOR_CONFIRMATION :
-        CWSWidgetContainer.State.INITIALIZED;  // Back to normal state.
-    this.webviewClient_.onInstallCompleted(
-        success, assert(this.installingItemId_));
-    this.installedItemId_ = this.installingItemId_;
-    this.installingItemId_ = null;
-
-    switch (result) {
-      case AppInstaller.Result.SUCCESS:
-        this.metricsRecorder_.recordInstall(
-            CWSWidgetContainer.MetricsRecorder.INSTALL.SUCCEEDED);
-        // Wait for the widget webview container to dispatch INSTALL_DONE.
-        break;
-      case AppInstaller.Result.CANCELLED:
-        this.metricsRecorder_.recordInstall(
-            CWSWidgetContainer.MetricsRecorder.INSTALL.CANCELLED);
-        // User cancelled the installation. Do nothing.
-        break;
-      case AppInstaller.Result.ERROR:
-        this.metricsRecorder_.recordInstall(
-            CWSWidgetContainer.MetricsRecorder.INSTALL.FAILED);
-        this.errorDialog_.show(
-            this.delegate_.strings.INSTALLATION_FAILED_MESSAGE, null, null,
-            null);
-        break;
-    }
-  }
-
-  /**
-   * Resolves the promise returned by {@code this.start} when widget is done
-   * with installing apps.
-   * @private
-   */
-  reportDone_() {
-    if (this.resolveStart_) {
-      this.resolveStart_(CWSWidgetContainer.ResolveReason.DONE);
-    }
-    this.resolveStart_ = null;
-  }
-
-  /**
-   * Finalizes the widget container state and returns the final app installation
-   * result. The widget should not be used after calling this. If called before
-   * promise returned by {@code this.start} is resolved, the reported result
-   * will be as if the widget was cancelled.
-   * @return {{result: CWSWidgetContainer.Result, installedItemId: ?string}}
-   */
-  finalizeAndGetResult() {
-    switch (this.state_) {
-      case CWSWidgetContainer.State.INSTALLING:
-        // Install is being aborted. Send the failure result.
-        // Cancels the install.
-        if (this.webviewClient_) {
-          this.webviewClient_.onInstallCompleted(
-              false, assert(this.installingItemId_));
-        }
-        this.installingItemId_ = null;
-
-        // Assumes closing the dialog as canceling the install.
-        this.state_ = CWSWidgetContainer.State.CANCELED_CLOSING;
-        break;
-      case CWSWidgetContainer.State.GETTING_ACCESS_TOKEN:
-      case CWSWidgetContainer.State.ACCESS_TOKEN_READY:
-      case CWSWidgetContainer.State.INITIALIZING:
-        this.metricsRecorder_.recordLoad(
-            CWSWidgetContainer.MetricsRecorder.LOAD.CANCELLED);
-        this.state_ = CWSWidgetContainer.State.CANCELED_CLOSING;
-        break;
-      case CWSWidgetContainer.State.WAITING_FOR_CONFIRMATION:
-        // This can happen if the dialog is closed by the user before Web Store
-        // widget replies with 'after_install'.
-        // Consider this success, as the app has actually been installed.
-        // TODO(tbarzic): Should the app be uninstalled in this case?
-        this.state_ = CWSWidgetContainer.State.INSTALLED_CLOSING;
-        break;
-      case CWSWidgetContainer.State.INSTALLED_CLOSING:
-      case CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING:
-      case CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING:
-        // Do nothing.
-        break;
-      case CWSWidgetContainer.State.INITIALIZED:
-        this.state_ = CWSWidgetContainer.State.CANCELED_CLOSING;
-        break;
-      default:
-        this.state_ = CWSWidgetContainer.State.CANCELED_CLOSING;
-        console.error('Invalid state.');
-    }
-
-    let result;
-    switch (this.state_) {
-      case CWSWidgetContainer.State.INSTALLED_CLOSING:
-        result = CWSWidgetContainer.Result.INSTALL_SUCCESSFUL;
-        this.metricsRecorder_.recordCloseDialog(
-            CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG.ITEM_INSTALLED);
-        break;
-      case CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING:
-        result = CWSWidgetContainer.Result.FAILED;
-        break;
-      case CWSWidgetContainer.State.CANCELED_CLOSING:
-        result = CWSWidgetContainer.Result.USER_CANCEL;
-        this.metricsRecorder_.recordCloseDialog(
-            CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG.USER_CANCELLED);
-        break;
-      case CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING:
-        result = CWSWidgetContainer.Result.WEBSTORE_LINK_OPENED;
-        this.metricsRecorder_.recordCloseDialog(
-            CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG
-                .WEBSTORE_LINK_OPENED);
-        break;
-      default:
-        result = CWSWidgetContainer.Result.USER_CANCEL;
-        this.metricsRecorder_.recordCloseDialog(
-            CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG.UNKNOWN_ERROR);
-    }
-
-    this.state_ = CWSWidgetContainer.State.UNINITIALIZED;
-
-    this.reset_();
-
-    return {result: result, installedItemId: this.installedItemId_};
-  }
-
-  /**
-   * Resets the widget.
-   * @private
-   */
-  reset_() {
-    if (this.state_ !== CWSWidgetContainer.State.UNINITIALIZED) {
-      console.error('Widget reset before its state was finalized.');
-    }
-
-    if (this.resolveStart_) {
-      this.resolveStart_(CWSWidgetContainer.ResolveReason.RESET);
-      this.resolveStart_ = null;
-    }
-
-    this.spinnerLayerController_.reset();
-
-    if (this.webviewClient_) {
-      this.webviewClient_.dispose();
-      this.webviewClient_ = null;
-    }
-
-    if (this.webview_) {
-      this.webviewContainer_.removeChild(this.webview_);
-      this.webview_ = null;
-    }
-
-    if (this.appInstaller_) {
-      this.appInstaller_.cancel();
-      this.appInstaller_ = null;
-    }
-
-    this.options_ = null;
-
-    if (this.errorDialog_.shown()) {
-      this.errorDialog_.hide();
-    }
-  }
-}
-
-/**
- * @enum {string}
- * @private
- */
-CWSWidgetContainer.State = {
-  UNINITIALIZED: 'CWSWidgetContainer.State.UNINITIALIZED',
-  GETTING_ACCESS_TOKEN: 'CWSWidgetContainer.State.GETTING_ACCESS_TOKEN',
-  ACCESS_TOKEN_READY: 'CWSWidgetContainer.State.ACCESS_TOKEN_READY',
-  INITIALIZING: 'CWSWidgetContainer.State.INITIALIZING',
-  INITIALIZE_FAILED_CLOSING:
-      'CWSWidgetContainer.State.INITIALIZE_FAILED_CLOSING',
-  INITIALIZED: 'CWSWidgetContainer.State.INITIALIZED',
-  INSTALLING: 'CWSWidgetContainer.State.INSTALLING',
-  WAITING_FOR_CONFIRMATION: 'CWSWidgetContainer.State.WAITING_FOR_CONFIRMATION',
-  INSTALLED_CLOSING: 'CWSWidgetContainer.State.INSTALLED_CLOSING',
-  OPENING_WEBSTORE_CLOSING: 'CWSWidgetContainer.State.OPENING_WEBSTORE_CLOSING',
-  CANCELED_CLOSING: 'CWSWidgetContainer.State.CANCELED_CLOSING'
-};
-Object.freeze(CWSWidgetContainer.State);
-
-/**
- * @enum {string}
- * @const
- */
-CWSWidgetContainer.Result = {
-  /** Install is done. The install app should be opened. */
-  INSTALL_SUCCESSFUL: 'CWSWidgetContainer.Result.INSTALL_SUCCESSFUL',
-  /** User cancelled the suggest app dialog. No message should be shown. */
-  USER_CANCEL: 'CWSWidgetContainer.Result.USER_CANCEL',
-  /** User clicked the link to web store so the dialog is closed. */
-  WEBSTORE_LINK_OPENED: 'CWSWidgetContainer.Result.WEBSTORE_LINK_OPENED',
-  /** Failed to load the widget. Error message should be shown. */
-  FAILED: 'CWSWidgetContainer.Result.FAILED'
-};
-Object.freeze(CWSWidgetContainer.Result);
-
-/**
- * The reason due to which the container is resolving {@code this.start}
- * promise.
- * @enum {string}
- */
-CWSWidgetContainer.ResolveReason = {
-  /** The widget container ended up in its final state. */
-  DONE: 'CWSWidgetContainer.ResolveReason.DONE',
-  /** The widget container is being reset. */
-  RESET: 'CWSWidgetContainer.CloserReason.RESET'
-};
-Object.freeze(CWSWidgetContainer.ResolveReason);
-
-
-CWSWidgetContainer.SpinnerLayerController = class {
-  /**
-   * Controls showing and hiding spinner layer.
-   * @param {!Element} spinnerLayer The spinner layer element.
-   */
-  constructor(spinnerLayer) {
-    /** @private {!Element} */
-    this.spinnerLayer_ = spinnerLayer;
-
-    /** @private {boolean} */
-    this.visible_ = false;
-
-    /**
-     * Set only if spinner is transitioning between visible and hidden states.
-     * Calling the function clears event handlers set for handling the
-     * transition, and updates spinner layer class list to its final state.
-     * @type {?function()}
-     * @private
-     */
-    this.clearTransition_ = null;
-
-    /**
-     * Reference to the timeout set to ensure {@code this.clearTransition_} gets
-     * called even if 'transitionend' event does not fire.
-     * @type {?number}
-     * @private
-     */
-    this.clearTransitionTimeout_ = null;
-
-    /**
-     * Element to be focused when the layer is hidden.
-     * @type {Element}
-     * @private
-     */
-    this.focusOnHide_ = null;
-
-    spinnerLayer.tabIndex = -1;
-
-    // Prevent default Tab key handling in order to prevent the widget from
-    // taking the focus while the spinner layer is active.
-    // NOTE: This assumes that there are no elements allowed to become active
-    // while the spinner is shown. Something smarter would be needed if this
-    // assumption becomes invalid.
-    spinnerLayer.addEventListener('keydown', this.handleKeyDown_.bind(this));
-  }
-
-  /**
-   * Sets element to be focused when the layer is hidden.
-   * @param {!Element} el
-   */
-  setElementToFocusOnHide(el) {
-    this.focusOnHide_ = el;
-  }
-
-  /**
-   * Prevents default Tab key handling in order to prevent spinner layer from
-   * losing focus.
-   * @param {Event} e The key down event.
-   * @private
-   */
-  handleKeyDown_(e) {
-    if (!this.visible_) {
-      return;
-    }
-    if (e.keyCode === 9 /* Tab */) {
-      e.preventDefault();
-    }
-  }
-
-  /**
-   * Resets the spinner layer controllers state, and makes sure the spinner
-   * layre gets hidden.
-   */
-  reset() {
-    this.visible_ = false;
-    this.focusOnHide_ = null;
-    if (this.clearTransition_) {
-      this.clearTransition_();
-    }
-  }
-
-  /**
-   * Sets alt text for the spinner layer.
-   * @param {string} text
-   */
-  setAltText(text) {
-    this.spinnerLayer_.setAttribute('aria-label', text);
-  }
-
-  /**
-   * Shows or hides the spinner layer and handles the layer's opacity
-   * transition.
-   * @param {boolean} visible Whether the layer should become visible.
-   */
-  setVisible(visible) {
-    if (this.visible_ === visible) {
-      return;
-    }
-
-    if (this.clearTransition_) {
-      this.clearTransition_();
-    }
-
-    this.visible_ = visible;
-
-    // Spinner should be shown during transition.
-    this.spinnerLayer_.classList.toggle('cws-widget-show-spinner', true);
-
-    if (this.visible_) {
-      this.spinnerLayer_.focus();
-    } else if (this.focusOnHide_) {
-      this.focusOnHide_.focus();
-    }
-
-    if (!this.visible_) {
-      this.spinnerLayer_.classList.add('cws-widget-hiding-spinner');
-    }
-
-    this.clearTransition_ = () => {
-      if (this.clearTransitionTimeout_) {
-        clearTimeout(this.clearTransitionTimeout_);
-      }
-      this.clearTransitionTimeout_ = null;
-
-      this.spinnerLayer_.removeEventListener(
-          'transitionend', this.clearTransition_);
-      this.clearTransition_ = null;
-
-      if (!this.visible_) {
-        this.spinnerLayer_.classList.remove('cws-widget-hiding-spinner');
-        this.spinnerLayer_.classList.remove('cws-widget-show-spinner');
-      }
-    };
-
-    this.spinnerLayer_.addEventListener('transitionend', this.clearTransition_);
-
-    // Ensure the transition state gets cleared, even if transitionend is not
-    // fired.
-    this.clearTransitionTimeout_ = setTimeout(() => {
-      this.clearTransitionTimeout_ = null;
-      this.clearTransition_();
-    }, 550 /* ms */);
-  }
-};
-
-/**
- * Utility methods and constants to record histograms.
- */
-CWSWidgetContainer.MetricsRecorder = class {
-  /**
-   * @param {!CWSWidgetContainerMetricsImpl} metricsImpl
-   */
-  constructor(metricsImpl) {
-    /** @private {!CWSWidgetContainerMetricsImpl} */
-    this.metricsImpl_ = metricsImpl;
-  }
-
-
-  /**
-   * @param {number} result Result of load, which must be defined in
-   *     CWSWidgetContainer.MetricsRecorder.LOAD.
-   */
-  recordLoad(result) {
-    if (0 <= result && result < 3) {
-      this.metricsImpl_.recordEnum('Load', result, 3);
-    }
-  }
-
-  /**
-   * @param {number} reason Reason of closing dialog, which must be defined in
-   *     CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG.
-   */
-  recordCloseDialog(reason) {
-    if (0 <= reason && reason < 4) {
-      this.metricsImpl_.recordEnum('CloseDialog', reason, 4);
-    }
-  }
-
-  /**
-   * @param {number} result Result of installation, which must be defined in
-   *     CWSWidgetContainer.MetricsRecorder.INSTALL.
-   */
-  recordInstall(result) {
-    if (0 <= result && result < 3) {
-      this.metricsImpl_.recordEnum('Install', result, 3);
-    }
-  }
-
-  recordShowDialog() {
-    this.metricsImpl_.recordUserAction('ShowDialog');
-  }
-
-  startLoad() {
-    this.metricsImpl_.startInterval('LoadTime');
-  }
-
-  finishLoad() {
-    this.metricsImpl_.recordInterval('LoadTime');
-  }
-};
-
-/**
- * @enum {number}
- * @const
- */
-CWSWidgetContainer.MetricsRecorder.LOAD = {
-  SUCCEEDED: 0,
-  CANCELLED: 1,
-  FAILED: 2,
-};
-
-/**
- * @enum {number}
- * @const
- */
-CWSWidgetContainer.MetricsRecorder.CLOSE_DIALOG = {
-  UNKNOWN_ERROR: 0,
-  ITEM_INSTALLED: 1,
-  USER_CANCELLED: 2,
-  WEBSTORE_LINK_OPENED: 3,
-};
-
-/**
- * @enum {number}
- * @const
- */
-CWSWidgetContainer.MetricsRecorder.INSTALL = {
-  SUCCEEDED: 0,
-  CANCELLED: 1,
-  FAILED: 2,
-};
diff --git a/ui/file_manager/file_manager/cws_widget/cws_widget_container_error_dialog.js b/ui/file_manager/file_manager/cws_widget/cws_widget_container_error_dialog.js
deleted file mode 100644
index de94474..0000000
--- a/ui/file_manager/file_manager/cws_widget/cws_widget_container_error_dialog.js
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015 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 {util} from '../common/js/util.m.js';
-// #import {BaseDialog} from 'chrome://resources/js/cr/ui/dialogs.m.js';
-
-/* #export */ class CWSWidgetContainerErrorDialog extends
-    cr.ui.dialogs.BaseDialog {
-  /**
-   * @param {HTMLElement} parentNode Node to be parent for this dialog.
-   */
-  constructor(parentNode) {
-    super(parentNode);
-
-    this.container.classList.add('files-ng');
-  }
-
-  /**
-   * Whether the dialog is showm.
-   * @return {boolean}
-   */
-  shown() {
-    return this.container.classList.contains('shown');
-  }
-
-  /**
-   * One-time initialization of DOM.
-   * @protected
-   * @override
-   */
-  initDom() {
-    super.initDom();
-    super.hasModalContainer = true;
-
-    this.frame.classList.add('cws-widget-error-dialog-frame');
-    const img = this.document_.createElement('div');
-    img.className = 'cws-widget-error-dialog-img';
-    this.frame.insertBefore(img, this.text);
-
-    this.title.hidden = true;
-    this.closeButton.hidden = true;
-    this.cancelButton.hidden = true;
-    this.text.classList.add('cws-widget-error-dialog-text');
-
-    // Don't allow OK button to lose focus, in order to prevent webview content
-    // from stealing focus.
-    // BaseDialog keeps focus by removing all other focusable elements from tab
-    // order (by setting their tabIndex to -1). This doesn't work for webviews
-    // because the webview embedder cannot access the webview DOM tree, and thus
-    // fails to remove elements in the webview from tab order.
-    this.okButton.addEventListener('blur', this.refocusOkButton_.bind(this));
-  }
-
-  /**
-   * Focuses OK button.
-   * @private
-   */
-  refocusOkButton_() {
-    if (this.shown()) {
-      this.okButton.focus();
-    }
-  }
-
-  /**
-   * @override
-   * @suppress {accessControls}
-   */
-  show_(...args) {
-    this.parentNode_ = util.getFilesAppModalDialogInstance();
-
-    super.show_(...args);
-
-    this.parentNode_.showModal();
-  }
-
-  /**
-   * @override
-   */
-  hide(...args) {
-    this.parentNode_.close();
-
-    super.hide(...args);
-  }
-}
diff --git a/ui/file_manager/file_manager/cws_widget/cws_widget_container_platform_delegate.js b/ui/file_manager/file_manager/cws_widget/cws_widget_container_platform_delegate.js
deleted file mode 100644
index 431478f6..0000000
--- a/ui/file_manager/file_manager/cws_widget/cws_widget_container_platform_delegate.js
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2015 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.
-
-/**
- * Strings required by the widget container.
- * @typedef {{
- *   UI_LOCALE: string,
- *   LINK_TO_WEBSTORE: string,
- *   INSTALLATION_FAILED_MESSAGE: string,
- *   LOADING_SPINNER_ALT: string,
- *   INSTALLING_SPINNER_ALT: string
- * }}
- */
-let CWSWidgetContainerStrings;
-
-/**
- * Functions for reporting metrics for the widget.
- * @typedef {{
- *   recordEnum: function(string, number, number),
- *   recordUserAction: function(string),
- *   startInterval: function(string),
- *   recordInterval: function(string)
- * }}
- */
-/* #export */ let CWSWidgetContainerMetricsImpl;
-
-/**
- * Type for delegate used by CWSWidgetContainer component to access Chrome
- * platform APIs.
- * @typedef {{
- *   strings: !CWSWidgetContainerStrings,
- *   metricsImpl: !CWSWidgetContainerMetricsImpl,
- *   installWebstoreItem: function(string, function(?string)),
- *   getInstalledItems: function(function(?Array<!string>)),
- *   requestWebstoreAccessToken: function(function(?string))
- * }}
- */
-/* #export */ let CWSWidgetContainerPlatformDelegate;
diff --git a/ui/file_manager/file_manager/externs/chrome_webstore_widget_private.js b/ui/file_manager/file_manager/externs/chrome_webstore_widget_private.js
deleted file mode 100644
index e7333d3..0000000
--- a/ui/file_manager/file_manager/externs/chrome_webstore_widget_private.js
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2015 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 */
-chrome.webstoreWidgetPrivate = {};
-
-/**
- * Installs the app with ID {@code itemId}.
- * @param {string} itemId
- * @param {boolean} silentInstall
- * @param {function()} callback
- */
-chrome.webstoreWidgetPrivate.installWebstoreItem = function(
-    itemId, silentInstall, callback) {};
diff --git a/ui/file_manager/file_manager/foreground/css/common.css b/ui/file_manager/file_manager/foreground/css/common.css
index e4a38d4a..323e7c22 100644
--- a/ui/file_manager/file_manager/foreground/css/common.css
+++ b/ui/file_manager/file_manager/foreground/css/common.css
@@ -125,8 +125,7 @@
 }
 
 /* Style for <button>s to have similar style with Polymer's <paper-button>. */
-.imitate-paper-button,
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button {
+.imitate-paper-button {
   background: transparent;
   border: 0;
   border-image: none;
@@ -149,17 +148,6 @@
   z-index: 0;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button {
-  border-radius: 4px;
-  font-weight: 500;
-  margin-inline-end: 0;
-  margin-inline-start: 5px;
-  min-height: 32px;
-  min-width: 70px;
-  padding: auto;
-  text-transform: none;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button {
   background-color: var(--cros-button-background-color-secondary);
   border: 0;
@@ -182,13 +170,6 @@
   z-index: 0;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-ok,
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-ok:hover {
-  background-color: var(--cros-button-background-color-primary);
-  color: var(--cros-button-label-color-primary);
-  order: 1;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-ok,
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-ok:hover {
   background-color: var(--cros-button-background-color-primary);
@@ -196,13 +177,6 @@
   order: 1;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-ok:hover {
-  background:
-      linear-gradient(var(--cros-button-background-color-primary-hover-overlay),
-                      var(--cros-button-background-color-primary-hover-overlay));
-              var(--cros-button-background-color-primary),
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-ok:hover {
   background:
       linear-gradient(var(--cros-button-background-color-primary-hover-overlay),
@@ -210,13 +184,6 @@
               var(--cros-button-background-color-primary);
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-ok[disabled],
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-ok[disabled]:hover {
-  background-color:
-      var(--cros-button-background-color-primary-disabled);
-  color: var(--cros-button-label-color-primary-disabled);
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-ok[disabled],
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-ok[disabled]:hover {
   background-color:
@@ -224,42 +191,22 @@
   color: var(--cros-button-label-color-primary-disabled);
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-cancel {
-  border: 1px solid var(--cros-button-stroke-color-secondary);
-  color: var(--cros-button-label-color-secondary);
-  order: 0;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-cancel {
   border: 1px solid var(--cros-button-stroke-color-secondary);
   color: var(--cros-button-label-color-secondary);
   order: 0;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-cancel:hover {
-  background: var(--cros-button-background-color-secondary-hover);
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-cancel:hover {
   background: var(--cros-button-background-color-secondary-hover);
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-cancel[disabled],
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button.cr-dialog-cancel[disabled]:hover  {
-  border: 1px solid var(--cros-button-stroke-color-secondary-disabled);
-  color: var(--cros-button-label-color-secondary-disabled);
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-cancel[disabled],
 .cr-dialog-container.files-ng .cr-dialog-buttons > button.cr-dialog-cancel[disabled]:hover  {
   border: 1px solid var(--cros-button-stroke-color-secondary-disabled);
   color: var(--cros-button-label-color-secondary-disabled);
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons > button:not(:active):focus {
-  box-shadow: 0 0 0 2px rgba(51, 103, 214, 0.5);
-}
-
 :root.focus-outline-visible .cr-dialog-container.files-ng .cr-dialog-buttons > button:not(:active):focus,
 :host-context(:root.focus-outline-visible) .cr-dialog-container.files-ng .cr-dialog-buttons > button:not(:active):focus {
   box-shadow: 0 0 0 2px var(--google-blue-500-rgb);
@@ -301,27 +248,10 @@
 }
 
 /* Pop-up dialogs. */
-.cr-dialog-container:not(.files-ng).shown {
-  background-color: rgba(0, 0, 0, 0.6);
-}
-
 .cr-dialog-container.files-ng.shown {
   background-color: rgba(var(--google-grey-900-rgb), 60%);
 }
 
-.cr-dialog-container:not(.files-ng) {
-  display: flex;
-  height: 100%;
-  left: 0;
-  overflow: auto;
-  position: absolute;
-  top: 0;
-  transition: opacity 250ms linear;
-  user-select: none;
-  width: 100%;
-  z-index: 9999;
-}
-
 .cr-dialog-container.files-ng {
   display: flex;
   height: 100%;
@@ -334,21 +264,6 @@
   z-index: 9999;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-frame {
-  background-color: var(--cros-bg-color);
-  border-radius: 2px;
-  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
-              0 2px 6px 0 rgba(0, 0, 0, 0.1);
-  color: var(--cros-text-color-primary);
-  cursor: default;
-  display: flex;
-  flex-direction: column;
-  margin: auto;
-  padding: 12px;
-  position: relative;
-  width: 386px;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-frame {
   background-color: var(--cros-bg-color);
   border-radius: 12px;
@@ -367,10 +282,6 @@
   position: relative;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-frame:focus {
-  outline: none;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-frame:focus {
   outline: none;
 }
@@ -397,15 +308,6 @@
   animation-timing-function: ease-in-out;
 }
 
-.cr-dialog-container:not(.files-ng).shown > .cr-dialog-frame {
-  opacity: 1;
-}
-
-.cr-dialog-container:not(.files-ng) .cr-dialog-frame {
-  opacity: 0;
-  transition: opacity 250ms;
-}
-
 .cr-dialog-container.files-ng.shown > .cr-dialog-frame {
   opacity: 1;
 }
@@ -415,18 +317,6 @@
   transition: opacity 100ms;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-title {
-  display: block;
-  font-size: 14px;
-  font-weight: 500;
-  margin-bottom: 10px;
-  margin-inline-end: 20px;
-  margin-inline-start: 4px;
-  margin-top: 4px;
-  white-space: nowrap;
-  word-wrap: normal;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-title {
   color: var(--cros-text-color-primary);
   display: block;
@@ -435,22 +325,10 @@
   margin-bottom: 16px;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-text {
-  font-size: 12px;
-  margin: 4px 4px 10px 4px;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-text {
   font-size: 14px;
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-text,
-.cr-dialog-container:not(.files-ng) .cr-dialog-title {
-  color: var(--cros-text-color-primary);
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-text,
 .cr-dialog-container.files-ng .cr-dialog-title {
   overflow-wrap: break-word;
@@ -464,18 +342,6 @@
   color: var(--cros-text-color-primary);
 }
 
-.cr-dialog-container:not(.files-ng) .cr-dialog-frame input {
-  box-sizing: border-box;
-  width: 100%;
-}
-
-.cr-dialog-container:not(.files-ng) .cr-dialog-buttons {
-  display: flex;
-  flex-direction: row;
-  justify-content: flex-end;
-  padding-top: 24px;
-}
-
 .cr-dialog-container.files-ng .cr-dialog-buttons {
   display: flex;
   flex-direction: row;
@@ -507,29 +373,6 @@
   right: unset !important;
 }
 
-html[dir='rtl'] .cr-dialog-container:not(.files-ng) .cr-dialog-close {
-  left: 0;
-  right: auto;
-}
-
-.cr-dialog-container:not(.files-ng) .cr-dialog-close:hover {
-  opacity: 0.9;
-}
-
-.cr-dialog-container:not(.files-ng) .cr-dialog-close:active {
-  opacity: 1;
-}
-
-.cr-dialog-container:not(.files-ng) .files-alert-dialog .cr-dialog-close,
-.cr-dialog-container:not(.files-ng) .files-confirm-dialog .cr-dialog-close {
-  display: none;
-}
-
-.cr-dialog-container:not(.files-ng) .files-alert-dialog .cr-dialog-text,
-.cr-dialog-container:not(.files-ng) .files-confirm-dialog .cr-dialog-text {
-  font-size: 14px;
-}
-
 /* Modal <dialog> container for Pop-up dialogs. */
 #files-app-modal-dialog {
   background-color: transparent;
diff --git a/ui/file_manager/file_manager/foreground/css/drive_welcome.css b/ui/file_manager/file_manager/foreground/css/drive_welcome.css
index b3ab0a28f0..dc9ee64d 100644
--- a/ui/file_manager/file_manager/foreground/css/drive_welcome.css
+++ b/ui/file_manager/file_manager/foreground/css/drive_welcome.css
@@ -23,16 +23,6 @@
 }
 
 /* Header welcome banner. */
-body:not(.files-ng) .drive-welcome.header {
-  background-color: rgb(79, 129, 232);
-  flex: none;
-  height: 130px;
-  overflow-x: hidden;
-  overflow-y: auto;
-  position: relative;
-  transition: height 180ms ease, visibility 0ms linear 180ms;
-}
-
 body.files-ng .drive-welcome.header {
   border-bottom: 1px solid var(--cr-separator-color, rgb(224, 224, 224));
   box-sizing: border-box;
@@ -47,12 +37,6 @@
   visibility: visible;
 }
 
-body:not(.files-ng) .dialog-container:not([drive-welcome='header'])
-.drive-welcome.header {
-  height: 0;
-  visibility: hidden;
-}
-
 body.files-ng .dialog-container:not([drive-welcome='header'])
 .drive-welcome.header {
   height: 0;
@@ -60,17 +44,6 @@
   visibility: hidden;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-wrapper {
-  color: white;
-  display: flex;
-  flex-direction: row;
-  left: 0;
-  padding-top: 21px;
-  position: absolute;
-  right: 0;
-  top: 0;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-wrapper {
   align-items: center;
   display: flex;
@@ -78,19 +51,6 @@
   height: 71px;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-icon {
-  background-color: white;
-  background-position: center;
-  background-size: 64px 64px;
-  border-radius: 4px;
-  flex: none;
-  height: 78px;
-  /* Icon should be centered within 128px banner with 25px margin. */
-  /* 4px at top adds to 21px padding-top in drive-welcom-header to make 25px. */
-  margin: 4px 25px 0 25px;
-  width: 78px;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-icon {
   background-position: center;
   background-size: 32px 32px;
@@ -102,38 +62,18 @@
   width: 32px;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-message {
-  margin-inline-end: 144px;
-  margin-inline-start: 20px;
-  z-index: 1;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-message {
   z-index: 1;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-title {
-  font-size: 21px;
-  font-weight: 500;
-  margin-bottom: 4px;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-title {
   margin-bottom: 2px;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-text {
-  font-size: 16px;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-text {
   display: inline;
 }
 
-body:not(.files-ng) .drive-welcome.header .drive-welcome-links {
-  z-index: 1;
-}
-
 body.files-ng .drive-welcome.header .drive-welcome-links {
   display: inline;
   margin-inline-start: 4px;
@@ -146,10 +86,6 @@
   padding: 0 4px;
 }
 
-body:not(.files-ng) .drive-welcome.header .banner-close {
-  top: 0;
-}
-
 html[dir='ltr'] .drive-welcome.header .banner-people {
   right: 38px;
 }
@@ -158,12 +94,6 @@
   left: 38px;
 }
 
-body:not(.files-ng) .drive-welcome.header .plain-link {
-  color: white;
-  font-size: 16px;
-  text-decoration: underline;
-}
-
 body.files-ng .drive-welcome.header .plain-link {
   color: var(--google-blue-600);
 }
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index faad374..e0a42ea 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -136,10 +136,6 @@
   overflow-y: hidden;
 }
 
-#directory-tree:not([files-ng]) .tree-item[section-start] {
-  border-top: 1px solid rgba(0, 0, 0, 10%);
-}
-
 #directory-tree[files-ng] .tree-item[section-start]::before {
   border-bottom: 1px solid var(--cr-separator-color, rgb(224, 224, 224));
   content: '';
@@ -148,15 +144,6 @@
   width: 100%;
 }
 
-#directory-tree:not([files-ng]) .tree-row {
-  align-items: center;
-  color: rgb(90, 90, 90);
-  cursor: pointer;
-  display: flex;
-  height: 40px;
-  padding: 0 3px;
-}
-
 #directory-tree[files-ng] .tree-row {
   cursor: pointer;
   height: auto;
@@ -281,23 +268,6 @@
   display: block;
 }
 
-#directory-tree:not([files-ng]) .tree-row > paper-ripple {
-  color: rgb(51, 103, 214);
-}
-
-#directory-tree:not([files-ng]) [renaming] > .tree-row > paper-ripple {
-  display: none;
-}
-
-#directory-tree:not([files-ng]) .tree-item.accepts > .tree-row,
-#directory-tree:not([files-ng]) .tree-row[selected] {
-  color: rgb(51, 103, 214);
-}
-
-#directory-tree:not([files-ng]):focus .tree-row[selected] {
-  background-color: rgb(216, 223, 240);
-}
-
 html:not(.col-resize) #directory-tree
     .tree-row:not([active]):not([selected]):hover > .file-row {
   background-color: var(--google-grey-100);
@@ -414,15 +384,6 @@
 
 /* A vertical splitter between the directory tree and the file list. It is
    a transparent area centered on the directory tree right border. */
-body:not(.files-ng) div.splitter {
-  cursor: col-resize;
-  flex: none;
-  margin: 0 -3px;
-  position: relative;
-  width: 6px;
-  z-index: 500;  /* Must be below the contextmenu (600). */
-}
-
 body.files-ng div.splitter {
   align-items: center;
   cursor: col-resize;
@@ -436,10 +397,6 @@
   z-index: 500;  /* Must be below the contextmenu (600). */
 }
 
-body:not(.files-ng) div.splitter .splitter-button {
-  display: none;
-}
-
 body.files-ng div.splitter .splitter-button {
   --hover-bg-color: rgba(0, 0, 0, 4%);
   --ink-color: rgba(0, 0, 0, 88%);
@@ -527,10 +484,6 @@
   border-top: 1px solid transparent;
 }
 
-body.check-select .dialog-header:not(.files-ng) {
-  color: rgb(90, 90, 90);
-}
-
 body.check-select .dialog-header.files-ng {
   color: var(--google-blue-600);
 }
@@ -560,14 +513,6 @@
   z-index: 1;
 }
 
-body:not(check-select) .dialog-header:not(.files-ng) cr-button {
-  --text-color: white;
-}
-
-body.check-select .dialog-header:not(.files-ng) cr-button {
-  --text-color: rgb(90, 90, 90);
-}
-
 .dialog-header.files-ng cr-button,
 .dialog-header.files-ng button {
   --hover-bg-color: rgba(0, 0, 0, 4%);
@@ -620,11 +565,6 @@
   display: none;
 }
 
-body:not(.check-select) .dialog-header:not(.files-ng) button,
-body:not(.check-select) .dialog-header:not(.files-ng) button:hover {
-  color: white;
-}
-
 body.check-select button,
 body.check-select button:hover {
   color: rgb(90, 90, 90);
@@ -641,11 +581,6 @@
 
 /** Avoid highlighting if element doesn't have focus by tab (tabindex=-1)
  *  or if focusing during mouse click event ":active" pseudo-selector. */
-html:not(.files-ng) .dialog-header
-    .menu-button:focus:not([tabindex='-1']):not(:active) {
-  background-color: rgba(255, 255, 255, 20%);
-}
-
 html.focus-outline-visible.files-ng .dialog-header
     .menu-button:focus:not([tabindex='-1']):not(:active) {
   background-color: rgba(255, 255, 255, 20%);
@@ -997,10 +932,6 @@
   font-weight: 500;
 }
 
-body:not(.files-ng) #files-selected-label {
-  margin-inline-start: 20px;
-}
-
 body.files-ng #files-selected-label {
   margin-inline-start: 8px;
 }
@@ -1018,10 +949,6 @@
   text-transform: none;
 }
 
-body:not(.files-ng) #cancel-selection-button {
-  background-color: transparent;
-}
-
 /* TODO(adanilo) document the calc() reason. */
 body.files-ng #cancel-selection-button {
   border: 1px solid transparent;
@@ -1029,20 +956,10 @@
   width: 36px;
 }
 
-body:not(.files-ng) #cancel-selection-button:focus:not([tabindex='-1']):not(:active) {
-  background-color: rgba(153, 153, 153, 20%);
-}
-
 html.focus-outline-visible body.files-ng #cancel-selection-button:focus:not([tabindex='-1']):not(:active) {
   border: 1px solid var(--google-blue-600);
 }
 
-body:not(.files-ng) #cancel-selection-button > span {
-  display: inline-block;
-  font-weight: 500;
-  vertical-align: middle;
-}
-
 body.files-ng #cancel-selection-button > span#cancel-selection-label {
   display: none;
 }
@@ -1057,10 +974,6 @@
   width: 20px;
 }
 
-body:not(.files-ng) #cancel-selection-button-wrapper {
-  width: 240px;  /* initial value, same as .dialog-navigation-list's width. */
-}
-
 #cancel-selection-button-wrapper {
   display: none;
 }
@@ -1094,13 +1007,6 @@
   font-size: 14px;
 }
 
-.dialog-header:not(.files-ng) #search-box cr-input {
-  --cr-input-border-bottom: 1px solid rgba(255, 255, 255, 50%);
-  --cr-input-color: white;
-  --cr-input-focus-color: white;
-  --cr-input-placeholder-color: rgba(255, 255, 255, 50%);
-}
-
 .dialog-header.files-ng #search-box cr-input {
   --cr-input-border-bottom: transparent;
   --cr-input-color: var(--google-grey-800);
@@ -1116,24 +1022,12 @@
   display: none;
 }
 
-.dialog-header:not(.files-ng) #search-box.has-cursor,
-.dialog-header:not(.files-ng) #search-box.has-text,
-.dialog-header:not(.files-ng) #search-box.hide-pending {
-  margin-inline-end: 12px;
-}
-
 .dialog-header.files-ng #search-box.has-cursor,
 .dialog-header.files-ng #search-box.has-text,
 .dialog-header.files-ng #search-box.hide-pending {
   margin-inline-end: 6px;
 }
 
-.dialog-header:not(.files-ng) #search-box.has-cursor cr-input,
-.dialog-header:not(.files-ng) #search-box.has-text cr-input,
-.dialog-header:not(.files-ng) #search-box.hide-pending cr-input {
-  width: 202px;
-}
-
 .dialog-header.files-ng #search-box.has-cursor cr-input,
 .dialog-header.files-ng #search-box.has-text cr-input,
 .dialog-header.files-ng #search-box.hide-pending cr-input {
@@ -1165,20 +1059,11 @@
   -webkit-mask-image: url(../images/files/ui/search_clear_filled.svg);
 }
 
-.dialog-header:not(.files-ng) #search-box .clear:focus {
-  background-color: rgba(255, 255, 255, 30%);
-}
-
 html[dir='rtl'] #search-box .clear {
   left: 0;
   right: auto;
 }
 
-.dialog-header:not(.files-ng) #search-box.has-cursor .clear,
-.dialog-header:not(.files-ng) #search-box.has-text .clear {
-  display: block;
-}
-
 .dialog-header.files-ng #search-box.has-cursor .clear,
 .dialog-header.files-ng #search-box.has-text .clear {
   display: flex;
@@ -1235,10 +1120,6 @@
   outline: none;
 }
 
-body:not(.files-ng) .dialog-footer {
-  padding: 8px 4px;
-}
-
 body.files-ng .dialog-footer {
   padding: 16px 24px;
 }
@@ -1256,25 +1137,6 @@
 }
 
 /* Copy style from paper-button for buttons on the footer. */
-body:not(.files-ng) .dialog-footer button {
-  background: transparent;
-  border: 0;
-  border-image: none;
-  border-radius: 2px;
-  box-sizing: border-box;
-  cursor: pointer;
-  margin: 0 0.29em;
-  min-width: 5.14em;
-  outline: none;
-  padding: 1px 16px;
-  position: relative;
-  text-align: center;
-  text-transform: uppercase;
-  transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
-  user-select: none;
-  z-index: 0;
-}
-
 body.files-ng .dialog-footer button {
   border: 0;
   border-image: none;
@@ -1333,22 +1195,12 @@
   color: var(--cros-button-label-color-primary-disabled);
 }
 
-body:not(.files-ng) .dialog-footer .primary,
-body:not(.files-ng) .dialog-footer .primary:hover {
-  background-color: rgb(51, 103, 214);
-  color: white;
-}
-
 body.files-ng .dialog-footer .primary,
 body.files-ng .dialog-footer .primary:hover {
   background-color: var(--cros-button-background-color-primary);
   color: var(--cros-button-label-color-primary);
 }
 
-body:not(.files-ng) .dialog-footer .secondary {
-  color: rgb(100, 100, 100);
-}
-
 body.files-ng .dialog-footer .secondary {
   background-color: var(--cros-button-background-color-secondary);
   border: 1px solid var(--cros-button-stroke-color-secondary);
@@ -1356,31 +1208,10 @@
   margin-inline-end: 8px;
 }
 
-body:not(.files-ng) .dialog-footer .secondary:hover {
-  color: rgb(51, 103, 214);
-}
-
 body.files-ng .dialog-footer .secondary:hover {
   background: var(--cros-button-background-color-secondary-hover);
 }
 
-body:not(.files-ng) .dialog-footer .select {
-  -webkit-appearance: none;
-  background: -webkit-image-set(
-     url(../images/common/disclosure_arrow_dk_grey_down.png) 1x,
-     url(../images/common/2x/disclosure_arrow_dk_grey_down.png) 2x) no-repeat
-     right transparent;
-  border: 0;
-  border-bottom: 1px solid rgb(207, 207, 207);
-  border-radius: 0;
-  color: rgb(51, 51, 51);
-  cursor: pointer;
-  margin-inline-start: 16px;
-  min-height: 21px;
-  outline: none;
-  padding: 0 12px 0 0;
-}
-
 body.files-ng .dialog-footer .select {
   background: -webkit-image-set(
      url(../images/common/disclosure_arrow_dk_grey_down.png) 1x,
@@ -1566,12 +1397,6 @@
   width: 8px;
 }
 
-.dialog-header:not(.files-ng) .breadcrumbs .separator {
-  background: -webkit-image-set(
-      url(../images/files/ui/arrow_right_white.png) 1x,
-      url(../images/files/ui/2x/arrow_right_white.png) 2x) center no-repeat;
-}
-
 .dialog-header.files-ng .breadcrumbs .separator {
   -webkit-mask-image: url(../images/files/ui/arrow_right.svg);
 }
@@ -1666,14 +1491,6 @@
   width: 16px;
 }
 
-body:not(.files-ng) .loading-indicator {
-  height: 3px;
-  left: 0;
-  position: absolute;
-  right: 0;
-  width: 100%;
-}
-
 body.files-ng .loading-indicator {
   left: calc(50% - 24px);
   position: absolute;
@@ -1681,27 +1498,6 @@
   top: 64px;
 }
 
-body:not(.files-ng) .list-view .loading-indicator {
-  top: 40px;
-}
-
-body:not(.files-ng) .thumbnail-view .loading-indicator {
-  top: 0;
-}
-
-body:not(.files-ng) .downloads-warning {
-  align-items: center;
-  background-color: rgb(79, 129, 232);
-  color: white;
-  display: flex;
-  flex: none;
-  flex-direction: row;
-  font-size: 14px;
-  height: 64px;
-  overflow: hidden;
-  transition: height 70ms linear;
-}
-
 body.files-ng .downloads-warning,
 body.files-ng .trash-warning {
   align-items: center;
@@ -1716,12 +1512,6 @@
   visibility: visible;
 }
 
-body:not(.files-ng) .downloads-warning a:link,
-body:not(.files-ng) .volume-warning a:link {
-  color: white;
-  flex: none;
-}
-
 body.files-ng .downloads-warning a:link,
 body.files-ng .volume-warning a:link {
   color: var(--google-blue-600);
@@ -1738,10 +1528,6 @@
   width: 20px;
 }
 
-body:not(.files-ng) .downloads-warning .warning-message {
-  margin-inline-end: 40px;
-}
-
 body.files-ng .warning-message .link-wrapper {
   display: inline;
 }
@@ -1753,11 +1539,6 @@
   text-decoration: none;
 }
 
-body:not(.files-ng) .downloads-warning[hidden] {
-  display: flex !important;  /* Overrides [hidden] for animation. */
-  height: 0;
-}
-
 body.files-ng .downloads-warning[hidden] {
   display: flex !important;  /* Overrides [hidden] for animation. */
   height: 0;
@@ -1773,20 +1554,6 @@
 }
 
 /* Drive space warning banner. */
-body:not(.files-ng) .volume-warning {
-  align-items: center;
-  animation: heightAnimation 70ms linear;
-  background-color: rgb(79, 129, 232);
-  color: white;
-  display: flex;
-  flex: none;
-  flex-direction: row;
-  font-size: 13px;
-  height: 64px;
-  overflow: hidden;
-  position: relative;
-}
-
 body.files-ng .volume-warning {
   align-items: center;
   border-bottom: 1px solid var(--cr-separator-color, rgb(224, 224, 224));
@@ -1804,11 +1571,6 @@
   visibility: visible;
 }
 
-body:not(.files-ng) .volume-warning[hidden] {
-  border-top-width: 0;
-  height: 0;
-}
-
 body.files-ng .volume-warning[hidden] {
   border-top-width: 0;
   display: flex !important;  /* Overrides [hidden] for animation. */
@@ -1827,12 +1589,6 @@
   width: 20px;
 }
 
-body:not(.files-ng) .volume-warning .drive-text {
-  flex: none;
-  font-size: 16px;
-  margin-inline-end: 51px;
-}
-
 body.files-ng .button-group {
   display: flex;
   flex: 0 0 auto;
@@ -1845,15 +1601,6 @@
   text-decoration-line: none;
 }
 
-body:not(.files-ng) .volume-warning .imitate-paper-button {
-  background-color: white;
-  border-radius: 2px;
-  color: rgb(79, 129, 232);
-  font-size: 13px;
-  font-weight: 500;
-  height: 2.5em;
-}
-
 body.files-ng .volume-warning .banner-button {
   border: 0;
   height: 32px;
@@ -1882,14 +1629,6 @@
   position: relative;
 }
 
-html[dir='ltr'] body:not(.files-ng) .banner-close {
-  right: 0;
-}
-
-html[dir='rtl'] body:not(.files-ng) .banner-close {
-  left: 0;
-}
-
 /* The cr.ui.Grid representing the detailed file list. */
 .thumbnail-grid {
   /* On the right side, we have less margin to pack items as long as they are
@@ -2234,11 +1973,6 @@
 /* Padding counterweights negative margins of items, thus eliminating scroll
    bar when it's not needed. Max height is set to fit 8 items before showing
    scroll bar. */
-body:not(.files-ng) #default-tasks-list {
-  max-height: 328px;
-  padding: 1px 0;
-}
-
 body.files-ng #default-tasks-list {
   border-top: solid 1px rgba(0, 0, 0, 14%);
   height: 240px;
@@ -2259,24 +1993,11 @@
   width: 100%
 }
 
-
-body:not(.files-ng) #default-tasks-list li {
-  height: 32px;
-  line-height: 32px;
-}
-
 body.files-ng #default-tasks-list li {
   height: 40px;
   line-height: 40px;
 }
 
-body:not(.files-ng) #default-tasks-list > li > * {
-  background-position: 5px center;
-  background-repeat: no-repeat;
-  background-size: 16px 16px;
-  padding-inline-start: 26px;
-}
-
 body.files-ng #default-tasks-list > li > * {
   background-position: 16px center;
   background-repeat: no-repeat;
@@ -2315,12 +2036,6 @@
   background-color: var(--google-blue-50);
 }
 
-body:not(.files-ng) #default-tasks-list:focus > li[selected],
-body:not(.files-ng) #default-tasks-list > li[selected] {
-  background-color: rgb(216, 223, 240);
-  outline: none;
-}
-
 body.files-ng #default-tasks-list:focus > li[selected],
 body.files-ng #default-tasks-list > li[selected] {
   background-color: var(--google-blue-50);
@@ -2529,12 +2244,6 @@
   width: 24px;
 }
 
-body:not(.files-ng) #list-container li .detail-icon {
-  height: 28px;
-  margin-inline-end: 6px;
-  width: 28px;
-}
-
 body.files-ng #list-container list li .detail-icon {
   color: var(--google-grey-700);
   height: 40px;
@@ -2641,60 +2350,6 @@
 }
 
 /* Invisible container for elements representing files while dragging. */
-body:not(.files-ng) #drag-container {
-  left: 0;
-  position: fixed;
-  top: 0;
-  z-index: -1;  /* below .dialog-container */
-}
-
-body:not(.files-ng) #drag-container .drag-contents {
-  background-color: #fafafa;
-  border: 1px solid #bbb;
-  border-radius: 3px;
-  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 20%);
-  display: flex;
-  flex-direction: row;
-  line-height: 0;
-  margin-bottom: 5px;
-  padding: 6px;
-  transition: opacity 200ms ease-in;
-}
-
-body:not(.files-ng) #drop-label {
-  background-color: rgba(0, 0, 0, 80%);
-  border-radius: 2px;
-  color: white;
-  display: none;  /* hidden until activated */
-  font-size: 12px;
-  height: 24px;
-  line-height: 24px;
-  padding: 0 8px;
-  position: absolute;
-  z-index: 1000;  /* same height as files-tooltip */
-}
-
-body:not(.files-ng) #drag-container .drag-contents.for-image  {
-  flex: none;
-  padding: 2px;
-}
-
-body:not(.files-ng) #drag-container .thumbnail-item {
-  display: flex;
-  flex-direction: row;
-}
-
-body:not(.files-ng) #drag-container .label {
-  flex: auto;
-  font-weight: bold;
-  line-height: 24px;
-  max-width: 320px;
-  overflow: hidden;
-  padding: 0 5px;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
 body.files-ng #drag-container {
   background-color: transparent;
   height: calc(12px + 40px + 8px + 8px);
@@ -3090,24 +2745,10 @@
   flex: none;
 }
 
-.cr-dialog-container:not(.files-ng) #default-task-dialog {
-  min-width: 300px;
-  width: auto;
-}
-
 .cr-dialog-container.files-ng #default-task-dialog {
   width: 352px;
 }
 
-.cr-dialog-container:not(.files-ng) #install-linux-package-dialog {
-  min-width: 300px;
-  width: 40%;
-}
-
-.cr-dialog-container:not(.files-ng) #install-linux-package-dialog .cr-dialog-text {
-  min-height: 30px;
-}
-
 .install-linux-package-details-frame {
   border: 1px solid lightgray;
   display: block;
@@ -3121,35 +2762,16 @@
   margin-top: 16px;
 }
 
-.cr-dialog-container:not(.files-ng) .install-linux-package-details-label {
-  color: #5a5a5a;
-  font-weight: 500;
-  margin-bottom: 10px;
-}
-
 .cr-dialog-container.files-ng .install-linux-package-details-label {
   margin-bottom: 10px;
 }
 
-.cr-dialog-container:not(.files-ng) .install-linux-package-detail-label {
-  color: #5a5a5a;
-  display: inline;
-  font-weight: 500;
-  margin-inline-end: 5px;
-}
-
 .cr-dialog-container.files-ng .install-linux-package-detail-label {
   color: var(--cros-text-color-primary);
   display: inline;
   margin-inline-end: 5px;
 }
 
-.cr-dialog-container:not(.files-ng) .install-linux-package-detail-value {
-  display: inline;
-  margin-bottom: 5px;
-  white-space: pre-wrap;
-}
-
 .cr-dialog-container.files-ng .install-linux-package-detail-value {
   color: var(--cros-text-color-secondary);
   display: inline;
@@ -3212,48 +2834,17 @@
   background-color: rgba(0, 0, 0, 8%);
 }
 
-body:not(.files-ng) #gear-menu,
-body:not(.files-ng) #share-menu,
-body:not(.files-ng) #sort-menu,
-body:not(.files-ng) #tasks-menu {
-  margin-top: 2px;
-}
-
 #gear-menu > cr-menu-item:not(.menuitem-button),
 #sort-menu > cr-menu-item {
   margin-inline-end: 50px;
 }
 
-.cr-dialog-container:not(.files-ng) #suggest-app-dialog {
-  background-color: #fff;
-  border: 0;
-  padding: 0;
-  width: auto;
-}
-
 .cr-dialog-container.files-ng #suggest-app-dialog.cr-dialog-frame {
   max-width: unset !important;
   min-width: unset !important;
   width: 735px;
 }
 
-.cr-dialog-container:not(.files-ng) .suggest-apps-dialog-title.cr-dialog-title {
-  /* Entire height: 44px (content-box 22px + padding 11px * 2) */
-  font-size: 16px;
-  line-height: 22px;
-  margin: 0;
-  padding: 11px 18px;
-}
-
-.cr-dialog-container:not(.files-ng) .suggest-apps-dialog-text.cr-dialog-text {
-  margin: 0;
-  padding: 0 20px 10px;
-}
-
-.cr-dialog-container:not(.files-ng) .cr-dialog-frame.error-dialog-frame {
-  width: 300px;
-}
-
 .error-dialog-frame .error-dialog-img {
   background-image: -webkit-image-set(
     url(chrome://theme/IDR_ERROR_NETWORK_GENERIC) 1x,
diff --git a/ui/file_manager/file_manager/foreground/css/tree.css b/ui/file_manager/file_manager/foreground/css/tree.css
index ed9d5de..53cb6480 100644
--- a/ui/file_manager/file_manager/foreground/css/tree.css
+++ b/ui/file_manager/file_manager/foreground/css/tree.css
@@ -71,12 +71,6 @@
   display: none;
 }
 
-/* Not used in files-ng: restrict by #directory-tree:not([files-ng]) to block
-   the trailing > * matching the files-ng .tree-row > .file-row structure. */
-#directory-tree:not([files-ng]) .tree-item > .tree-row > * {
-  display: inline-block;
-}
-
 .tree-label {
   white-space: pre;
 }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
index 8f3c437..a05c8cb 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
+++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
@@ -80,12 +80,12 @@
 }
 
 #contentPanel[metadata-box-active] {
-  margin-right: 320px;
+  margin-inline-end: 320px;
 }
 
 :host-context(html[dir='rtl']) #contentPanel[metadata-box-active] {
-  margin-left: 320px;
-  margin-right: auto;
+  margin-inline-end: auto;
+  margin-inline-start: 320px;
 }
 
 #innerContentPanel {
@@ -153,19 +153,6 @@
   display: flex;
 }
 
-:host(:not([files-ng])) cr-button,
-:host(:not([files-ng])) files-icon-button {
-  --ink-color: currentColor;
-  border: none;
-  border-radius: 2px;
-  color: currentColor;
-  height: 32px;
-  margin: 0 8px;
-  min-width: 32px;
-  padding: 0;
-  text-transform: uppercase;
-}
-
 :host([files-ng]) cr-button {
   --hover-bg-color: rgba(255, 255, 255, 4%);
   --ink-color: rgba(255, 255, 255, 88%);
@@ -214,10 +201,6 @@
   display: none;
 }
 
-:host(:not([files-ng])) #back-button > .icon {
-  display: none;
-}
-
 :host([files-ng]) #back-button > .icon {
   -webkit-mask-image: url(../images/files/ui/back.svg);
 }
@@ -237,10 +220,6 @@
   -webkit-mask-image: url(../images/files/ui/delete_ng.svg);
 }
 
-:host(:not([files-ng])) #info-button {
-  display: none;
-}
-
 #metadata-button {
   --files-toggle-ripple-bg-color: white;
   --files-toggle-ripple-activated-opacity: 0.3;
@@ -258,11 +237,6 @@
   -webkit-mask-image: url(../images/files/ui/info.svg);
 }
 
-:host(:not([files-ng])) cr-button:focus:not(:active) {
-  box-shadow: 0 0 0 1px rgba(66, 133, 244, 50%);
-  font-weight: bold;
-}
-
 :host-context(html.focus-outline-visible.files-ng) cr-button:not(:active):focus {
   border: 2px solid var(--google-blue-300);
 }
@@ -309,11 +283,11 @@
 
 @media only screen and (max-width: 720px) {
   #contentPanel[metadata-box-active] #innerContentPanel {
-    padding-left: 4px;
-    padding-right: 4px;
+    padding-inline-end: 4px;
+    padding-inline-start: 4px;
   }
   #contentPanel[metadata-box-active] {
-    margin-right: 250px;
+    margin-inline-end: 250px;
   }
 }
 
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index bf24a86..1473c7d3 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -95,7 +95,6 @@
     ":task_history.m",
     ":thumbnail_loader.m",
     ":toolbar_controller.m",
-    ":web_store_utils.m",
     ":webui_command_extender.m",
   ]
 }
@@ -157,7 +156,6 @@
     ":task_history",
     ":thumbnail_loader",
     ":toolbar_controller",
-    ":web_store_utils",
     ":webui_command_extender",
   ]
 }
@@ -179,7 +177,6 @@
     "//ui/file_manager/file_manager/externs/background/progress_center.js",
     "//ui/file_manager/file_manager/externs/background_window.js",
     "//ui/file_manager/file_manager/externs/chrome_echo_private.js",
-    "//ui/file_manager/file_manager/externs/chrome_webstore_widget_private.js",
     "//ui/file_manager/file_manager/externs/command_handler_deps.js",
     "//ui/file_manager/file_manager/externs/css_rule.js",
     "//ui/file_manager/file_manager/externs/directory_change_event.js",
@@ -1076,7 +1073,6 @@
     ":file_transfer_controller.m",
     ":naming_controller.m",
     ":task_history.m",
-    ":web_store_utils.m",
     "metadata:metadata_model.m",
     "ui:combobutton.m",
     "ui:default_task_dialog.m",
@@ -2054,17 +2050,6 @@
   extra_deps = [ ":modulize" ]
 }
 
-js_library("web_store_utils") {
-  deps = [ ":constants" ]
-}
-
-js_library("web_store_utils.m") {
-  sources = [ "$root_gen_dir/ui/file_manager/file_manager/foreground/js/web_store_utils.m.js" ]
-  deps = [ ":constants.m" ]
-
-  extra_deps = [ ":modulize" ]
-}
-
 js_library("webui_command_extender") {
   deps = [
     "//ui/webui/resources/js:cr",
@@ -2176,7 +2161,6 @@
     "task_history.js",
     "thumbnail_loader.js",
     "toolbar_controller.js",
-    "web_store_utils.js",
     "webui_command_extender.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 d0ca45a9..ab034470 100644
--- a/ui/file_manager/file_manager/foreground/js/launch_param.js
+++ b/ui/file_manager/file_manager/foreground/js/launch_param.js
@@ -7,14 +7,6 @@
 // #import {DialogType} from './dialog_type.m.js';
 // clang-format on
 
-/**
- * @typedef {{
- *   overrideCwsContainerUrlForTest: (string|undefined),
- *   overrideCwsContainerOriginForTest: (string|undefined)
- * }}
- */
-/* #export */ let SuggestAppDialogState;
-
 /* #export */ class LaunchParam {
   /**
    * @param {!Object} unformatted Unformatted option.
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 e160137f..6b81207 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -93,7 +93,6 @@
 //
 // <include src="constants.js">
 // <include src="crossover_search_utils.js">
-// <include src="web_store_utils.js">
 // <include src="ui/multi_menu.js">
 // <include src="ui/multi_menu_button.js">
 // <include src="ui/combobutton.js">
@@ -103,11 +102,6 @@
 // <include src="metadata/metadata_provider.js">
 // <include src="metadata/metadata_request.js">
 //
-// <include src="../../cws_widget/app_installer.js">
-// <include src="../../cws_widget/cws_webview_client.js">
-// <include src="../../cws_widget/cws_widget_container.js">
-// <include src="../../cws_widget/cws_widget_container_error_dialog.js">
-//
 // <include src="actions_controller.js">
 // <include src="actions_model.js">
 // <include src="android_app_list_model.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 9c0edb9..acf7527 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -128,7 +128,6 @@
     "//ui/file_manager/file_manager/externs/background/import_history.js",
     "//ui/file_manager/file_manager/externs/background_window.js",
     "//ui/file_manager/file_manager/externs/chrome_echo_private.js",
-    "//ui/file_manager/file_manager/externs/chrome_webstore_widget_private.js",
     "//ui/file_manager/file_manager/externs/css_rule.js",
     "//ui/file_manager/file_manager/externs/drag_target.js",
     "//ui/file_manager/file_manager/externs/drive_dialog_controller.js",
diff --git a/ui/file_manager/file_manager/foreground/js/web_store_utils.js b/ui/file_manager/file_manager/foreground/js/web_store_utils.js
deleted file mode 100644
index 8f5682c..0000000
--- a/ui/file_manager/file_manager/foreground/js/web_store_utils.js
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.
-
-/**
- * @fileoverview
- * @suppress {uselessCode} Temporary suppress because of the line exporting.
- */
-
-// #import {constants} from './constants.m.js';
-
-/**
- * Namespace for web store utility functions.
- * @namespace
- */
-const webStoreUtils = {};
-
-/**
- * Location of the Chrome Web Store.
- *
- * @const
- * @type {string}
- */
-webStoreUtils.CHROME_WEB_STORE_URL = 'https://chrome.google.com/webstore';
-
-/**
- * Base URL of apps list in the Chrome Web Store.
- *
- * @const
- * @type {string}
- */
-webStoreUtils.WEB_STORE_HANDLER_BASE_URL =
-    'https://chrome.google.com/webstore/category/collection/file_handlers';
-
-/**
- * Returns URL of the Chrome Web Store which show apps supporting the given
- * file-extension and mime-type.
- *
- * @param {?string} extension Extension of the file (with the first dot).
- * @param {?string} mimeType Mime type of the file.
- * @return {string} URL
- */
-webStoreUtils.createWebStoreLink = (extension, mimeType) => {
-  if (!extension || constants.EXECUTABLE_EXTENSIONS.indexOf(extension) !== -1) {
-    return webStoreUtils.CHROME_WEB_STORE_URL;
-  }
-
-  if (extension[0] === '.') {
-    extension = extension.substr(1);
-  } else {
-    console.warn('Please pass an extension with a dot to createWebStoreLink.');
-  }
-
-  let url = webStoreUtils.WEB_STORE_HANDLER_BASE_URL;
-  url += '?_fe=' + extension.toLowerCase().replace(/[^\w]/g, '');
-
-  // If a mime is given, add it into the URL.
-  if (mimeType) {
-    url += '&_fmt=' + mimeType.replace(/[^-\w\/]/g, '');
-  }
-  return url;
-};
-
-// eslint-disable-next-line semi,no-extra-semi
-/* #export */ {webStoreUtils};
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 978d661b..3fa8bc076 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -24,7 +24,6 @@
     <link rel="stylesheet" href="foreground/css/file_status.css">
     <link rel="stylesheet" href="foreground/css/file_types.css">
     <link rel="stylesheet" href="foreground/css/common.css">
-    <link rel="stylesheet" href="cws_widget/cws_widget_container.css">
 
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="foreground/js/elements_importer.js"></script>
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 7b057078d..ce44f3d 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -43,7 +43,6 @@
     "syncFileSystem",
     "unlimitedStorage",
     "wallpaper",
-    "webstoreWidgetPrivate",
     "webview"
   ],
   "webview": {
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index ad44835..1ba088f 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -125,20 +125,8 @@
 
       <!-- The AudioPlayer app pages and scripts. -->
       <include name="IDR_AUDIO_PLAYER_MANIFEST" file="audio_player/manifest.json" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_BACKGROUND_JS" file="audio_player/js/background_scripts.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_BACKGROUND_HTML" file="audio_player/background.html" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_AUDIO_PLAYER_HTML" file="audio_player/elements/audio_player.html" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_AUDIO_PLAYER_JS" file="audio_player/elements/audio_player.js" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_CONTROL_PANEL_HTML" file="audio_player/elements/control_panel.html" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_CONTROL_PANEL_JS" file="audio_player/elements/control_panel.js" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_REPEAT_BUTTON_HTML" file="audio_player/elements/repeat_button.html" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_REPEAT_BUTTON_JS" file="audio_player/elements/repeat_button.js" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_HTML" file="audio_player/elements/track_list.html" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_JS" file="audio_player/elements/track_list.js" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_METADATA_WORKER_JS" file="audio_player/js/metadata_worker.js" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER" file="audio_player/audio_player.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_MODULE" file="audio_player/audio_player_module.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_AUDIO_PLAYER_JS" file="audio_player/js/audio_player_scripts.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ICON_FAVICON_16" file="audio_player/icons/audio-player-favicon-16.png" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ICON_FAVICON_32" file="audio_player/icons/audio-player-favicon-32.png" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ICON_16" file="audio_player/icons/audio-player-16.png" type="BINDATA" />
@@ -161,12 +149,6 @@
       <include name="IDR_FILE_MANAGER_IMG_GALLERY_CURSOR_CROP" file="gallery/images/100/cursor_crop.png" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_IMG_GALLERY_2X_CURSOR_CROP" file="gallery/images/200/cursor_crop.png" type="BINDATA" />
 
-      <!-- Chrome Webstore widget dialog -->
-      <include name="IDR_FILE_MANAGER_WEBSTORE_WIDGET_APP_INSTALLER_JS" file="file_manager/cws_widget/app_installer.js" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_WEBSTORE_WIDGET_CWS_WEBVIEW_CLIENT_JS" file="file_manager/cws_widget/cws_webview_client.js" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_WEBSTORE_WIDGET_CWS_WIDGET_CONTAINER_JS" file="file_manager/cws_widget/cws_widget_container.js" type="BINDATA" />
-      <include name="IDR_FILE_MANAGER_WEBSTORE_WIDGET_CWS_WIDGET_CONTAINER_ERROR_DIALOG_JS" file="file_manager/cws_widget/cws_widget_container_error_dialog.js" type="BINDATA" />
-
       <!-- Image loader extension manifest and scripts. -->
       <if expr="chromeos">
         <include name="IDR_IMAGE_LOADER_MANIFEST" file="image_loader/manifest.json" type="BINDATA" />
diff --git a/ui/gfx/font_list.h b/ui/gfx/font_list.h
index e2c3072..a0d96fa 100644
--- a/ui/gfx/font_list.h
+++ b/ui/gfx/font_list.h
@@ -83,6 +83,10 @@
   //
   // ui::ResourceBundle may call this function more than once when UI language
   // is changed.
+  //
+  // Unit Tests should use ScopedDefaultFontDescription instead of calling this
+  // directly, to avoid leaving the default font description in an unexpected
+  // state for tests that run in the same process.
   static void SetDefaultFontDescription(const std::string& font_description);
 
   // Returns a new FontList with the same font names but resized and the given
diff --git a/ui/gfx/test/gfx_util.h b/ui/gfx/test/gfx_util.h
index 1c9015d..cb59626 100644
--- a/ui/gfx/test/gfx_util.h
+++ b/ui/gfx/test/gfx_util.h
@@ -7,6 +7,7 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/font_list.h"
 
 namespace gfx {
 
@@ -16,6 +17,18 @@
 class RectF;
 class SizeF;
 
+// Tests should use this scoped setter, instead of calling
+// SetDefaultFontDescription directly.
+class ScopedDefaultFontDescription {
+ public:
+  explicit ScopedDefaultFontDescription(const std::string& font_description) {
+    FontList::SetDefaultFontDescription(font_description);
+  }
+  ~ScopedDefaultFontDescription() {
+    FontList::SetDefaultFontDescription(std::string());
+  }
+};
+
 #define EXPECT_AXIS_TRANSFORM2D_EQ(a, b) \
   EXPECT_PRED_FORMAT2(::gfx::AssertAxisTransform2dFloatEqual, a, b)
 
diff --git a/ui/latency/latency_tracker.cc b/ui/latency/latency_tracker.cc
index 7fe3a92..05cf568 100644
--- a/ui/latency/latency_tracker.cc
+++ b/ui/latency/latency_tracker.cc
@@ -141,6 +141,29 @@
   CONFIRM_EVENT_TIMES_EXIST(original_timestamp, gpu_swap_end_timestamp);
   base::TimeDelta dur = gpu_swap_end_timestamp - original_timestamp;
 
+  if (first_frame) {
+    if (total_update_events_ > 0) {
+      // If we have some data from previous scroll, report it to UMA.
+      UMA_HISTOGRAM_MEDIUM_TIMES("Event.Latency.ScrollUpdate.TotalDuration",
+                                 total_update_duration_);
+      UMA_HISTOGRAM_MEDIUM_TIMES("Event.Latency.ScrollUpdate.JankyDuration",
+                                 janky_update_duration_);
+
+      UMA_HISTOGRAM_COUNTS_10000("Event.Latency.ScrollUpdate.TotalEvents",
+                                 total_update_events_);
+      UMA_HISTOGRAM_COUNTS_10000("Event.Latency.ScrollUpdate.JankyEvents",
+                                 janky_update_events_);
+    }
+
+    total_update_events_ = 0;
+    janky_update_events_ = 0;
+    total_update_duration_ = base::TimeDelta{};
+    janky_update_duration_ = base::TimeDelta{};
+  }
+
+  total_update_events_++;
+  total_update_duration_ += dur;
+
   // When processing first frame in a scroll, we do not have any other frames to
   // compare it to, and thus no way to detect the jank.
   if (!first_frame) {
@@ -161,13 +184,20 @@
     if (!prev_scroll_update_reported_) {
       // The information about previous GestureScrollUpdate was not reported:
       // check whether it's janky by comparing to the current frame and report.
-      UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank",
-                            prev_frames_taken > frames_taken + 0.5);
+      if (prev_frames_taken > frames_taken + 0.5) {
+        UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank", true);
+        janky_update_events_++;
+        janky_update_duration_ += prev_duration_;
+      } else {
+        UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank", false);
+      }
     }
 
     // The current GestureScrollUpdate is janky compared to the previous one.
     if (frames_taken > prev_frames_taken + 0.5) {
       UMA_HISTOGRAM_BOOLEAN("Event.Latency.ScrollJank", true);
+      janky_update_events_++;
+      janky_update_duration_ += dur;
 
       // Since we have reported the current event as janky, there is no need to
       // report anything about it on the next iteration, as we would like to
diff --git a/ui/latency/latency_tracker.h b/ui/latency/latency_tracker.h
index 2affdc1..8eebfd0 100644
--- a/ui/latency/latency_tracker.h
+++ b/ui/latency/latency_tracker.h
@@ -36,6 +36,10 @@
 
   base::TimeDelta prev_duration_;
   bool prev_scroll_update_reported_ = false;
+  int total_update_events_ = 0;
+  int janky_update_events_ = 0;
+  base::TimeDelta total_update_duration_;
+  base::TimeDelta janky_update_duration_;
 
   void ReportUkmScrollLatency(
       const InputMetricEvent& metric_event,
diff --git a/ui/native_theme/DIR_METADATA b/ui/native_theme/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/native_theme/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/resources/DIR_METADATA b/ui/resources/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/resources/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/surface/DIR_METADATA b/ui/surface/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/surface/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/ui/views/controls/tabbed_pane/DIR_METADATA b/ui/views/controls/tabbed_pane/DIR_METADATA
deleted file mode 100644
index d1a6630..0000000
--- a/ui/views/controls/tabbed_pane/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>Views"
-}
diff --git a/ui/views/controls/textfield/DIR_METADATA b/ui/views/controls/textfield/DIR_METADATA
deleted file mode 100644
index d1a6630..0000000
--- a/ui/views/controls/textfield/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "Internals>Views"
-}
diff --git a/ui/webui/resources/cr_components/chromeos/quick_unlock/DIR_METADATA b/ui/webui/resources/cr_components/chromeos/quick_unlock/DIR_METADATA
deleted file mode 100644
index b39cd583..0000000
--- a/ui/webui/resources/cr_components/chromeos/quick_unlock/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "OS>Systems>Settings"
-}
\ No newline at end of file
diff --git a/ui/wm/DIR_METADATA b/ui/wm/DIR_METADATA
deleted file mode 100644
index f31293e3..0000000
--- a/ui/wm/DIR_METADATA
+++ /dev/null
@@ -1,3 +0,0 @@
-monorail: {
-  component: "UI"
-}
diff --git a/url/android/DIR_METADATA b/url/android/DIR_METADATA
deleted file mode 100644
index fb07a25..0000000
--- a/url/android/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Core"
-}
\ No newline at end of file
diff --git a/url/ipc/DIR_METADATA b/url/ipc/DIR_METADATA
deleted file mode 100644
index fb07a25..0000000
--- a/url/ipc/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Core"
-}
\ No newline at end of file
diff --git a/url/third_party/mozilla/DIR_METADATA b/url/third_party/mozilla/DIR_METADATA
deleted file mode 100644
index fb07a25..0000000
--- a/url/third_party/mozilla/DIR_METADATA
+++ /dev/null
@@ -1,11 +0,0 @@
-# Metadata information for this directory.
-#
-# For more information on DIR_METADATA files, see:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
-#
-# For the schema of this file, see Metadata message:
-#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
-
-monorail {
-  component: "Internals>Core"
-}
\ No newline at end of file