diff --git a/DEPS b/DEPS
index d4efff5..ffa4032 100644
--- a/DEPS
+++ b/DEPS
@@ -195,11 +195,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '398ecf1876f13ffb7911fbf5b800cca8d4e8f90c',
+  'skia_revision': 'e3d6db4c3fac08059bcaa744ce429665fa10a8c1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '1f2195b49c6d7611165ebd149b2825f27693930c',
+  'v8_revision': '2a00f38a34d5c3dffd2ef5cd1f538534ce7d66af',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -207,7 +207,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3d1609516687c6040bcfaa2ba94454f102076171',
+  'angle_revision': '97013e85adfceabb4e4c4d95178e186481b82362',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -215,7 +215,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': '184443e8d77994d568436a2213e1d12e433d73b4',
+  'pdfium_revision': '82b1c03b687687f98916b4f439b576d03bb99965',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -258,7 +258,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': '8178c8db633526170c98908ecd6ea7db3cdd7bab',
+  'catapult_revision': '788aa6fd2c18c8c4ee84e5c15c86f451def6be07',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -266,7 +266,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': '661b3a4411c6258802a13351cafa2e453b7de4c1',
+  'devtools_frontend_revision': '447a462be3f9d44c89994c8a5eb44b738d4c8dc6',
   # 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.
@@ -318,11 +318,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '320c6c87b2ed980d4c7622230976d40ad0fc54a1',
+  'dawn_revision': '8575cb3ec773d43a86fe68eece70ae02cad6cfc5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'c2e5361f375a0354cd0eb7cf6dea1e0c19555a4f',
+  'quiche_revision': 'd8fb72d5ad9cb8ae3499b07b37b7857d88d26794',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -896,7 +896,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'e7f2169b3665555121389754010b19882b563f1b',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'c08c71bedfbb76a839518633ce2ea92feaf36163',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -916,7 +916,7 @@
   },
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '48b037ba0de5eecc97baf6e1d0133c4cc58485b1',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'a1f3db690c654bc3c74381c61d4071c578e5f398',
 
   'src/third_party/flac':
     Var('chromium_git') + '/chromium/deps/flac.git' + '@' + 'af862024c8c8fa0ae07ced05e89013d881b00596',
@@ -1543,7 +1543,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@53daab94768a1972d367c5390ece7305b9fe4526',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a3467211f5c01108d0c8845a9add9514dcda7d83',
     'condition': 'checkout_src_internal',
   },
 
@@ -1551,7 +1551,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'q7fJGoUZfsUaMt-ae3SViUsR1NdBaXcLVuaNOAI_8CMC',
+        'version': 'HZNHFa2CcUZB-FO9DToAmE5qKZsX_2h2bM8NbJPrGd0C',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1562,7 +1562,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': 'gK0jWjCbv2pog8c8oLyWz6k0XrWhmsjGf59KCV9AIcgC',
+        'version': 'NDPCcgJvuhM3F7KyVFnMa4mftVlWMdK9ysK3cuxhi2oC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index d3f1617a..8119776d 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2067,6 +2067,7 @@
     "system/tray/tray_info_label_unittest.cc",
     "system/tray/tri_view_unittest.cc",
     "system/unified/feature_pods_container_view_unittest.cc",
+    "system/unified/notification_counter_view_unittest.cc",
     "system/unified/page_indicator_view_unittest.cc",
     "system/unified/quiet_mode_feature_pod_controller_unittest.cc",
     "system/unified/top_shortcuts_view_unittest.cc",
diff --git a/ash/app_list/views/privacy_container_view.cc b/ash/app_list/views/privacy_container_view.cc
index 0d8ee6cd..5ce5dd65 100644
--- a/ash/app_list/views/privacy_container_view.cc
+++ b/ash/app_list/views/privacy_container_view.cc
@@ -11,6 +11,7 @@
 #include "ash/app_list/model/search/search_result.h"
 #include "ash/app_list/views/assistant/assistant_privacy_info_view.h"
 #include "ash/app_list/views/suggested_content_info_view.h"
+#include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
 #include "ui/views/layout/box_layout.h"
 
@@ -87,7 +88,9 @@
   // the top of the results list.
   const bool should_show_container =
       should_show_assistant || should_show_suggested_content;
-  set_container_score(should_show_container ? INT_MAX : -1);
+  set_container_score(should_show_container
+                          ? AppListConfig::instance().privacy_container_score()
+                          : -1);
   return should_show_container ? 1 : 0;
 }
 
diff --git a/ash/clipboard/clipboard_history_controller.cc b/ash/clipboard/clipboard_history_controller.cc
index eb16f9d..b2e2b65f 100644
--- a/ash/clipboard/clipboard_history_controller.cc
+++ b/ash/clipboard/clipboard_history_controller.cc
@@ -139,10 +139,6 @@
   DCHECK(IsMenuShowing());
   auto command = context_menu_->GetSelectedMenuItemCommand();
 
-  // Force close the context menu. Failure to do so before dispatching our
-  // synthetic key event will result in the context menu consuming the event.
-  context_menu_->Cancel();
-
   // If no menu item is currently selected, we'll fallback to the first item.
   menu_delegate_->ExecuteCommand(command.value_or(0), event_flags);
 }
@@ -157,20 +153,8 @@
 
   std::unique_ptr<ui::SimpleMenuModel> menu_model =
       std::make_unique<ui::SimpleMenuModel>(menu_delegate_.get());
-  menu_model->AddTitle(
-      ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
-          IDS_CLIPBOARD_MENU_CLIPBOARD));
-  int index = 0;
-  for (const auto& item : clipboard_items_) {
-    menu_model->AddItemWithIcon(index++, resource_manager_->GetLabel(item),
-                                resource_manager_->GetImageModel(item));
-  }
-  menu_model->AddSeparator(ui::MenuSeparatorType::NORMAL_SEPARATOR);
-  menu_model->AddItemWithIcon(
-      index++,
-      ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
-          IDS_CLIPBOARD_MENU_DELETE_ALL),
-      ui::ImageModel::FromVectorIcon(ash::kDeleteIcon));
+  for (size_t i = 0; i < clipboard_items_.size(); ++i)
+    menu_model->AddItem(i, base::string16());
 
   context_menu_ =
       std::make_unique<ClipboardHistoryMenuModelAdapter>(std::move(menu_model));
@@ -179,15 +163,14 @@
 
 void ClipboardHistoryController::MenuOptionSelected(int index,
                                                     int event_flags) {
+  // Force close the context menu. Failure to do so before dispatching our
+  // synthetic key event will result in the context menu consuming the event.
+  DCHECK(context_menu_);
+  context_menu_->Cancel();
+
   auto selected_item = clipboard_items_.begin();
   std::advance(selected_item, index);
 
-  if (selected_item == clipboard_items_.end()) {
-    // The last option in the menu is used to delete history.
-    clipboard_history_->Clear();
-    return;
-  }
-
   auto* clipboard = GetClipboard();
   std::unique_ptr<ui::ClipboardData> original_data;
 
diff --git a/ash/clipboard/clipboard_history_controller.h b/ash/clipboard/clipboard_history_controller.h
index e397496..bb5bcd9 100644
--- a/ash/clipboard/clipboard_history_controller.h
+++ b/ash/clipboard/clipboard_history_controller.h
@@ -44,6 +44,11 @@
   // Returns the history which tracks what is being copied to the clipboard.
   const ClipboardHistory* history() const { return clipboard_history_.get(); }
 
+  // Do not use it. Will be removed soon.
+  const std::vector<ClipboardHistoryItem>& clipboard_items() const {
+    return clipboard_items_;
+  }
+
   // Returns the resource manager which gets labels and images for items copied
   // to the clipboard.
   const ClipboardHistoryResourceManager* resource_manager() const {
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.cc b/ash/clipboard/clipboard_history_menu_model_adapter.cc
index 971abed..7250bbe37 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.cc
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.cc
@@ -4,6 +4,9 @@
 
 #include "ash/clipboard/clipboard_history_menu_model_adapter.h"
 
+#include "ash/clipboard/clipboard_history_controller.h"
+#include "ash/clipboard/views/clipboard_history_item_view.h"
+#include "ash/shell.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/ui_base_types.h"
 #include "ui/gfx/geometry/rect.h"
@@ -57,4 +60,26 @@
   return root_view_->GetSubmenu()->GetBoundsInScreen();
 }
 
+views::MenuItemView* ClipboardHistoryMenuModelAdapter::AppendMenuItem(
+    views::MenuItemView* menu,
+    ui::MenuModel* model,
+    int index) {
+  const int item_index = model->GetCommandIdAt(index);
+  views::MenuItemView* container = menu->AppendMenuItem(item_index);
+
+  // Margins are managed by `ClipboardHistoryItemView`.
+  container->SetMargins(/*top_margin=*/0, /*bottom_margin=*/0);
+
+  const auto& items =
+      Shell::Get()->clipboard_history_controller()->clipboard_items();
+
+  std::unique_ptr<ClipboardHistoryItemView> item_view =
+      ClipboardHistoryItemView::CreateFromClipboardHistoryItem(
+          items[item_index], container);
+  item_view->Init();
+  container->AddChildView(std::move(item_view));
+
+  return container;
+}
+
 }  // namespace ash
diff --git a/ash/clipboard/clipboard_history_menu_model_adapter.h b/ash/clipboard/clipboard_history_menu_model_adapter.h
index db5e0ef..a4ccb70 100644
--- a/ash/clipboard/clipboard_history_menu_model_adapter.h
+++ b/ash/clipboard/clipboard_history_menu_model_adapter.h
@@ -54,6 +54,11 @@
   gfx::Rect GetMenuBoundsInScreenForTest() const;
 
  private:
+  // views::MenuModelAdapter:
+  views::MenuItemView* AppendMenuItem(views::MenuItemView* menu,
+                                      ui::MenuModel* model,
+                                      int index) override;
+
   // The model which holds the contents of the menu.
   std::unique_ptr<ui::SimpleMenuModel> const model_;
   // The root MenuItemView which contains all child MenuItemViews. Owned by
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
index 482dbc0..acb1b86 100644
--- a/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.cc
@@ -6,6 +6,7 @@
 
 #include "ash/clipboard/clipboard_history_item.h"
 #include "ui/views/controls/image_view.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/fill_layout.h"
 
 namespace {
@@ -13,17 +14,56 @@
 // The preferred height for the bitmap.
 constexpr int kBitmapHeight = 64;
 
-// The contents area's rounded corners.
-constexpr gfx::RoundedCornersF kRoundedCorners = gfx::RoundedCornersF(4);
+// The margins of the delete button.
+constexpr gfx::Insets kDeleteButtonMargins =
+    gfx::Insets(/*top=*/4, /*left=*/0, /*bottom=*/0, /*right=*/4);
 }  // namespace
 
 namespace ash {
 
+////////////////////////////////////////////////////////////////////////////////
+// ClipboardHistoryBitmapItemView::BitmapContentsView
+
+class ClipboardHistoryBitmapItemView::BitmapContentsView
+    : public ClipboardHistoryBitmapItemView::ContentsView {
+ public:
+  explicit BitmapContentsView(ClipboardHistoryBitmapItemView* container)
+      : ContentsView(container) {}
+  BitmapContentsView(const BitmapContentsView& rhs) = delete;
+  BitmapContentsView& operator=(const BitmapContentsView& rhs) = delete;
+  ~BitmapContentsView() override = default;
+
+  // ContentsView:
+  DeleteButton* CreateDeleteButton() override {
+    auto delete_button_container = std::make_unique<views::View>();
+    auto* layout_manager = delete_button_container->SetLayoutManager(
+        std::make_unique<views::BoxLayout>(
+            views::BoxLayout::Orientation::kHorizontal));
+    layout_manager->set_main_axis_alignment(
+        views::BoxLayout::MainAxisAlignment::kEnd);
+    layout_manager->set_cross_axis_alignment(
+        views::BoxLayout::CrossAxisAlignment::kStart);
+
+    auto delete_button = std::make_unique<DeleteButton>(container_);
+    delete_button->SetVisible(false);
+    delete_button->SetBorder(views::CreateEmptyBorder(kDeleteButtonMargins));
+    DeleteButton* delete_button_ptr =
+        delete_button_container->AddChildView(std::move(delete_button));
+    AddChildView(std::move(delete_button_container));
+
+    return delete_button_ptr;
+  }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ClipboardHistoryBitmapItemView
+
 ClipboardHistoryBitmapItemView::ClipboardHistoryBitmapItemView(
     const ClipboardHistoryItem& item,
     views::MenuItemView* container)
     : ClipboardHistoryItemView(container),
-      original_bitmap_(&(item.data().bitmap())) {}
+      original_image_(
+          gfx::ImageSkia::CreateFrom1xBitmap(item.data().bitmap())) {}
 
 ClipboardHistoryBitmapItemView::~ClipboardHistoryBitmapItemView() = default;
 
@@ -33,18 +73,15 @@
 
 std::unique_ptr<ClipboardHistoryBitmapItemView::ContentsView>
 ClipboardHistoryBitmapItemView::CreateContentsView() {
-  auto contents_view = std::make_unique<ContentsView>();
+  auto contents_view = std::make_unique<BitmapContentsView>(this);
   contents_view->SetLayoutManager(std::make_unique<views::FillLayout>());
 
   auto image_view = std::make_unique<views::ImageView>();
-  const gfx::ImageSkia img_from_bitmap =
-      gfx::ImageSkia::CreateFrom1xBitmap(*original_bitmap_);
-  image_view->SetImage(img_from_bitmap);
+  image_view->SetImage(original_image_);
   image_view->SetPreferredSize(gfx::Size(INT_MAX, kBitmapHeight));
-  image_view->SetPaintToLayer();
-  image_view->layer()->SetRoundedCornerRadius(kRoundedCorners);
   image_view_ = contents_view->AddChildView(std::move(image_view));
 
+  contents_view->InstallDeleteButton();
   return contents_view;
 }
 
@@ -54,8 +91,7 @@
 }
 
 gfx::Size ClipboardHistoryBitmapItemView::CalculateTargetImageSize() const {
-  const gfx::Size image_size(original_bitmap_->width(),
-                             original_bitmap_->height());
+  const gfx::Size image_size = image_view_->GetImage().size();
   const double width_ratio = image_size.width() / double(width());
   const double height_ratio = image_size.height() / double(height());
 
diff --git a/ash/clipboard/views/clipboard_history_bitmap_item_view.h b/ash/clipboard/views/clipboard_history_bitmap_item_view.h
index 5ac6ed65..fc816b8 100644
--- a/ash/clipboard/views/clipboard_history_bitmap_item_view.h
+++ b/ash/clipboard/views/clipboard_history_bitmap_item_view.h
@@ -7,8 +7,6 @@
 
 #include "ash/clipboard/views/clipboard_history_item_view.h"
 
-class SkBitmap;
-
 namespace views {
 class ImageView;
 }  // namespace views
@@ -27,6 +25,8 @@
   ~ClipboardHistoryBitmapItemView() override;
 
  private:
+  class BitmapContentsView;
+
   // ClipboardHistoryItemView:
   const char* GetClassName() const override;
   std::unique_ptr<ContentsView> CreateContentsView() override;
@@ -35,8 +35,8 @@
   // Calculates the target size of the image to show.
   gfx::Size CalculateTargetImageSize() const;
 
-  // Bitmap stored in the clipboard data.
-  const SkBitmap* const original_bitmap_;
+  // The image from the bitmap which is stored in the clipboard data.
+  const gfx::ImageSkia original_image_;
 
   // Owned by view hierarchy.
   views::ImageView* image_view_ = nullptr;
diff --git a/ash/clipboard/views/clipboard_history_item_view.cc b/ash/clipboard/views/clipboard_history_item_view.cc
index 12d602b..9e71442 100644
--- a/ash/clipboard/views/clipboard_history_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_item_view.cc
@@ -8,8 +8,13 @@
 #include "ash/clipboard/clipboard_history_util.h"
 #include "ash/clipboard/views/clipboard_history_bitmap_item_view.h"
 #include "ash/clipboard/views/clipboard_history_text_item_view.h"
+#include "ash/resources/vector_icons/vector_icons.h"
+#include "base/strings/utf_string_conversions.h"
 #include "ui/base/clipboard/clipboard_data.h"
-#include "ui/views/border.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_item_view.h"
 #include "ui/views/layout/fill_layout.h"
@@ -19,14 +24,56 @@
 // The insets within the contents view.
 constexpr gfx::Insets kContentsInsets(/*vertical=*/4, /*horizontal=*/16);
 
+// The size of the `DeleteButton`.
+constexpr int kDeleteButtonSizeDip = 16;
+
 // The view responding to mouse click or gesture tap events.
 class MainButton : public views::Button {
  public:
-  MainButton(views::ButtonListener* listener) : Button(listener) {}
+  explicit MainButton(ash::ClipboardHistoryItemView* container)
+      : Button(container), container_(container) {
+    SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+    SetAccessibleName(base::ASCIIToUTF16(std::string(GetClassName())));
+  }
   MainButton(const MainButton& rhs) = delete;
   MainButton& operator=(const MainButton& rhs) = delete;
   ~MainButton() override = default;
+
+ private:
+  // views::Button:
+  const char* GetClassName() const override { return "MainButton"; }
+
+  void StateChanged(ButtonState old_state) override {
+    if (GetState() != ButtonState::STATE_HOVERED &&
+        GetState() != ButtonState::STATE_NORMAL) {
+      return;
+    }
+
+    container_->SelectionWillChange(GetState() == ButtonState::STATE_HOVERED);
+  }
+
+  void PaintButtonContents(gfx::Canvas* canvas) override {
+    if (GetState() != ButtonState::STATE_HOVERED &&
+        GetState() != ButtonState::STATE_PRESSED) {
+      return;
+    }
+
+    // Highlight the background when the menu item is under selection.
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+
+    const ui::NativeTheme::ColorId color_id =
+        ui::NativeTheme::kColorId_FocusedMenuItemBackgroundColor;
+    flags.setColor(GetNativeTheme()->GetSystemColor(color_id));
+
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    canvas->DrawRect(GetLocalBounds(), flags);
+  }
+
+  // The parent view.
+  ash::ClipboardHistoryItemView* const container_;
 };
+
 }  // namespace
 
 namespace ash {
@@ -34,19 +81,52 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ClipboardHistoryItemView::ContentsView
 
-ClipboardHistoryItemView::ContentsView::ContentsView() {
+ClipboardHistoryItemView::ContentsView::ContentsView(
+    ClipboardHistoryItemView* container)
+    : container_(container) {
   SetEventTargeter(std::make_unique<views::ViewTargeter>(this));
   SetBorder(views::CreateEmptyBorder(kContentsInsets));
 }
 
 ClipboardHistoryItemView::ContentsView::~ContentsView() = default;
 
-// The contents view's default behavior is to reject any event. It gives the
-// main button of the menu item a chance to handle events.
+void ClipboardHistoryItemView::ContentsView::SelectionWillChange(
+    bool target_is_selected) {
+  // Update |delete_button_|'s visiblity if the selection state switches.
+  if (target_is_selected ^ delete_button_->GetVisible())
+    delete_button_->SetVisible(target_is_selected);
+}
+
+void ClipboardHistoryItemView::ContentsView::InstallDeleteButton() {
+  delete_button_ = CreateDeleteButton();
+}
+
+// Accepts the event only when |delete_button_| should be the handler.
 bool ClipboardHistoryItemView::ContentsView::DoesIntersectRect(
     const views::View* target,
     const gfx::Rect& rect) const {
-  return false;
+  return delete_button_->GetVisible() && delete_button_->HitTestRect(rect);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ClipboardHistoryItemView::DeleteButton
+
+ClipboardHistoryItemView::DeleteButton::DeleteButton(
+    views::ButtonListener* listener)
+    : views::ImageButton(listener) {
+  const gfx::ImageSkia icon_image =
+      gfx::CreateVectorIcon(kDeleteIcon, kDeleteButtonSizeDip, SK_ColorBLACK);
+  SetImage(views::ImageButton::STATE_NORMAL, icon_image);
+  SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY);
+  SetAccessibleName(base::ASCIIToUTF16(std::string(GetClassName())));
+  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
+  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
+}
+
+ClipboardHistoryItemView::DeleteButton::~DeleteButton() = default;
+
+const char* ClipboardHistoryItemView::DeleteButton::GetClassName() const {
+  return "DeleteButton";
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -78,10 +158,15 @@
 
 void ClipboardHistoryItemView::Init() {
   SetLayoutManager(std::make_unique<views::FillLayout>());
+
+  // Ensures that MainButton is below any other child views.
   AddChildView(std::make_unique<MainButton>(this));
 
-  auto contents_view = CreateContentsView();
-  AddChildView(std::move(contents_view));
+  contents_view_ = AddChildView(CreateContentsView());
+}
+
+void ClipboardHistoryItemView::SelectionWillChange(bool target_is_selected) {
+  contents_view_->SelectionWillChange(target_is_selected);
 }
 
 gfx::Size ClipboardHistoryItemView::CalculatePreferredSize() const {
diff --git a/ash/clipboard/views/clipboard_history_item_view.h b/ash/clipboard/views/clipboard_history_item_view.h
index 9539284..e29a0e0 100644
--- a/ash/clipboard/views/clipboard_history_item_view.h
+++ b/ash/clipboard/views/clipboard_history_item_view.h
@@ -5,7 +5,7 @@
 #ifndef ASH_CLIPBOARD_VIEWS_CLIPBOARD_HISTORY_ITEM_VIEW_H_
 #define ASH_CLIPBOARD_VIEWS_CLIPBOARD_HISTORY_ITEM_VIEW_H_
 
-#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
 #include "ui/views/view_targeter_delegate.h"
 
 namespace views {
@@ -31,18 +31,51 @@
   // Initializes the menu item.
   void Init();
 
+  // Called when the selection state will change. `target_is_selected` indicates
+  // the target selection state.
+  void SelectionWillChange(bool target_is_selected);
+
  protected:
+  // The button to delete the menu item and its corresponding clipboard data.
+  class DeleteButton : public views::ImageButton {
+   public:
+    explicit DeleteButton(views::ButtonListener* listener);
+    DeleteButton(const DeleteButton& rhs) = delete;
+    DeleteButton& operator=(const DeleteButton& rhs) = delete;
+    ~DeleteButton() override;
+
+   private:
+    // views::ImageButton:
+    const char* GetClassName() const override;
+  };
+
   // Used by subclasses to draw contents, such as text or bitmaps.
   class ContentsView : public views::View, public views::ViewTargeterDelegate {
    public:
-    ContentsView();
+    explicit ContentsView(ClipboardHistoryItemView* container);
     ContentsView(const ContentsView& rhs) = delete;
     ContentsView& operator=(const ContentsView& rhs) = delete;
     ~ContentsView() override;
 
+    // Install DeleteButton on the contents view.
+    void InstallDeleteButton();
+
+    // Called when the parent's selection state will change.
+    void SelectionWillChange(bool target_is_selected);
+
+   protected:
+    virtual DeleteButton* CreateDeleteButton() = 0;
+
+    // The parent of ContentsView.
+    ClipboardHistoryItemView* const container_;
+
+   private:
     // views::ViewTargeterDelegate:
     bool DoesIntersectRect(const views::View* target,
                            const gfx::Rect& rect) const override;
+
+    // Owned by the view hierarchy.
+    DeleteButton* delete_button_ = nullptr;
   };
 
   explicit ClipboardHistoryItemView(views::MenuItemView* container);
@@ -58,6 +91,8 @@
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   views::MenuItemView* const container_;
+
+  ContentsView* contents_view_ = nullptr;
 };
 
 }  // namespace ash
diff --git a/ash/clipboard/views/clipboard_history_text_item_view.cc b/ash/clipboard/views/clipboard_history_text_item_view.cc
index 7ba99890..b053c9b9 100644
--- a/ash/clipboard/views/clipboard_history_text_item_view.cc
+++ b/ash/clipboard/views/clipboard_history_text_item_view.cc
@@ -9,16 +9,50 @@
 #include "ash/shell.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_config.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view_class_properties.h"
 
 namespace {
 
 // The preferred height for the label.
 constexpr int kLabelPreferredHeight = 16;
+
+// The margins of the delete button.
+constexpr gfx::Insets kDeleteButtonMargins =
+    gfx::Insets(/*top=*/0, /*left=*/0, /*bottom=*/0, /*right=*/4);
 }  // namespace
 
 namespace ash {
 
+////////////////////////////////////////////////////////////////////////////////
+// ClipboardHistoryTextItemView::TextContentsView
+
+class ClipboardHistoryTextItemView::TextContentsView
+    : public ClipboardHistoryTextItemView::ContentsView {
+ public:
+  explicit TextContentsView(ClipboardHistoryItemView* container)
+      : ContentsView(container) {}
+  TextContentsView(const TextContentsView& rhs) = delete;
+  TextContentsView& operator=(const TextContentsView& rhs) = delete;
+  ~TextContentsView() override = default;
+
+ private:
+  // ContentsView:
+  DeleteButton* CreateDeleteButton() override {
+    auto delete_button = std::make_unique<DeleteButton>(container_);
+    delete_button->SetVisible(false);
+    delete_button->SetBorder(views::CreateEmptyBorder(kDeleteButtonMargins));
+    return AddChildView(std::move(delete_button));
+  }
+
+  const char* GetClassName() const override {
+    return "ClipboardHistoryTextItemView::TextContentsView";
+  }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// ClipboardHistoryTextItemView
+
 ClipboardHistoryTextItemView::ClipboardHistoryTextItemView(
     const ClipboardHistoryItem& item,
     views::MenuItemView* container)
@@ -36,15 +70,22 @@
 
 std::unique_ptr<ClipboardHistoryTextItemView::ContentsView>
 ClipboardHistoryTextItemView::CreateContentsView() {
-  auto contents_view = std::make_unique<ContentsView>();
-  contents_view->SetLayoutManager(std::make_unique<views::FillLayout>());
+  auto contents_view = std::make_unique<TextContentsView>(this);
+  auto* layout =
+      contents_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::Orientation::kHorizontal));
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CrossAxisAlignment::kCenter);
 
-  auto label = std::make_unique<views::Label>(text_);
+  auto* label =
+      contents_view->AddChildView(std::make_unique<views::Label>(text_));
   label->SetPreferredSize(gfx::Size(INT_MAX, kLabelPreferredHeight));
   label->SetFontList(views::MenuConfig::instance().font_list);
   label->SetMultiLine(false);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  contents_view->AddChildView(std::move(label));
+  layout->SetFlexForView(label, /*flex_weights=*/1);
+
+  contents_view->InstallDeleteButton();
 
   return contents_view;
 }
diff --git a/ash/clipboard/views/clipboard_history_text_item_view.h b/ash/clipboard/views/clipboard_history_text_item_view.h
index 3ec6868..f3b8388 100644
--- a/ash/clipboard/views/clipboard_history_text_item_view.h
+++ b/ash/clipboard/views/clipboard_history_text_item_view.h
@@ -25,6 +25,8 @@
   ~ClipboardHistoryTextItemView() override;
 
  private:
+  class TextContentsView;
+
   // ClipboardHistoryItemView:
   const char* GetClassName() const override;
   std::unique_ptr<ContentsView> CreateContentsView() override;
diff --git a/ash/public/cpp/app_list/app_list_config.h b/ash/public/cpp/app_list/app_list_config.h
index 277f2e8..a41cf7625 100644
--- a/ash/public/cpp/app_list/app_list_config.h
+++ b/ash/public/cpp/app_list/app_list_config.h
@@ -176,6 +176,7 @@
     return max_search_result_list_items_;
   }
 
+  double privacy_container_score() const { return privacy_container_score_; }
   double app_tiles_container_score() const {
     return app_tiles_container_score_;
   }
@@ -472,8 +473,11 @@
   // Max number of search result list items in the launcher suggestion window.
   const size_t max_search_result_list_items_ = 5;
 
-  // Scores for the three containers within the search box view. These are
-  // displayed in high-to-low order.
+  // Scores for the containers within the search box view. These are displayed
+  // in high-to-low order.
+  // The privacy container is not always visible, but when available it should
+  // always be the first item underneath the search box.
+  const double privacy_container_score_ = 4.0;
   const double app_tiles_container_score_ = 3.0;
   const double answer_card_container_score_ = 2.0;
   const double results_list_container_score_ = 1.0;
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index d3abdc9..e8f02e8 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -87,6 +87,9 @@
 const base::Feature kMediaSessionNotification{"MediaSessionNotification",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kMediaNotificationsCounter{
+    "MediaNotificationsCounter", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kMovablePartialScreenshot{
     "MovablePartialScreenshot", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index b8715f8..7fd84ae 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -85,6 +85,10 @@
 // TODO(beccahughes): Remove after launch. (https://crbug.com/897836)
 ASH_PUBLIC_EXPORT extern const base::Feature kMediaSessionNotification;
 
+// Removes media notifications from the notification counter in the status area.
+// TODO(crbug.com/1111881): Remove when OS media controls launched.
+ASH_PUBLIC_EXPORT extern const base::Feature kMediaNotificationsCounter;
+
 // Enables resizing/moving the selection region for partial screenshot.
 ASH_PUBLIC_EXPORT extern const base::Feature kMovablePartialScreenshot;
 
diff --git a/ash/shelf/back_button.cc b/ash/shelf/back_button.cc
index 8282af26..3537ea5d 100644
--- a/ash/shelf/back_button.cc
+++ b/ash/shelf/back_button.cc
@@ -9,6 +9,7 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_focus_cycler.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/metrics/user_metrics.h"
@@ -40,7 +41,10 @@
 void BackButton::PaintButtonContents(gfx::Canvas* canvas) {
   // Use PaintButtonContents instead of SetImage so the icon gets drawn at
   // |GetCenterPoint| coordinates instead of always in the center.
-  gfx::ImageSkia img = CreateVectorIcon(kShelfBackIcon, SK_ColorWHITE);
+  gfx::ImageSkia img = CreateVectorIcon(
+      kShelfBackIcon, AshColorProvider::Get()->GetContentLayerColor(
+                          AshColorProvider::ContentLayerType::kButtonIconColor,
+                          AshColorProvider::AshColorMode::kDark));
   canvas->DrawImageInt(img, GetCenterPoint().x() - img.width() / 2,
                        GetCenterPoint().y() - img.height() / 2);
 }
diff --git a/ash/shelf/home_button.cc b/ash/shelf/home_button.cc
index a281c55..1e997d27 100644
--- a/ash/shelf/home_button.cc
+++ b/ash/shelf/home_button.cc
@@ -13,6 +13,7 @@
 #include "ash/shelf/shelf_focus_cycler.h"
 #include "ash/shelf/shelf_navigation_widget.h"
 #include "ash/shell.h"
+#include "ash/style/ash_color_provider.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/check_op.h"
 #include "base/metrics/user_metrics.h"
@@ -140,7 +141,9 @@
     cc::PaintFlags fg_flags;
     fg_flags.setAntiAlias(true);
     fg_flags.setStyle(cc::PaintFlags::kStroke_Style);
-    fg_flags.setColor(ShelfConfig::Get()->shelf_icon_color());
+    fg_flags.setColor(AshColorProvider::Get()->GetContentLayerColor(
+        AshColorProvider::ContentLayerType::kButtonIconColor,
+        AshColorProvider::AshColorMode::kDark));
 
     if (controller_.IsAssistantAvailable()) {
       // active: 100% alpha, inactive: 54% alpha
diff --git a/ash/system/unified/notification_counter_view.cc b/ash/system/unified/notification_counter_view.cc
index a984c150..ac21f3f 100644
--- a/ash/system/unified/notification_counter_view.cc
+++ b/ash/system/unified/notification_counter_view.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "ash/media/media_notification_constants.h"
 #include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller_impl.h"
@@ -27,10 +28,6 @@
 
 namespace {
 
-// Maximum count of notification shown by a number label. "+" icon is shown
-// instead if it exceeds this limit.
-constexpr size_t kTrayNotificationMaxCount = 9;
-
 constexpr double kTrayNotificationCircleIconRadius = 8;
 
 // The size of the number font inside the icon. Should be updated when
@@ -107,6 +104,20 @@
       Shell::Get()->session_controller();
   size_t notification_count =
       message_center::MessageCenter::Get()->NotificationCount();
+
+  // If flag is set, do not include media notifications in count.
+  // TODO(crbug.com/1111881) This code can be removed when OS media controls are
+  // launched (expected by M90).
+  if (base::FeatureList::IsEnabled(features::kMediaNotificationsCounter)) {
+    const message_center::NotificationList::Notifications& visible =
+        message_center::MessageCenter::Get()->GetVisibleNotifications();
+    notification_count = std::count_if(
+        visible.begin(), visible.end(),
+        [](message_center::Notification* notification) {
+          return notification->notifier_id().id != kMediaSessionNotifierId;
+        });
+  }
+
   if (notification_count == 0 ||
       message_center::MessageCenter::Get()->IsQuietMode() ||
       !session_controller->ShouldShowNotificationTray() ||
diff --git a/ash/system/unified/notification_counter_view.h b/ash/system/unified/notification_counter_view.h
index ba3ba843..5fbf695 100644
--- a/ash/system/unified/notification_counter_view.h
+++ b/ash/system/unified/notification_counter_view.h
@@ -5,14 +5,20 @@
 #ifndef ASH_SYSTEM_UNIFIED_NOTIFICATION_COUNTER_VIEW_H_
 #define ASH_SYSTEM_UNIFIED_NOTIFICATION_COUNTER_VIEW_H_
 
+#include "ash/ash_export.h"
 #include "ash/public/cpp/session/session_observer.h"
 #include "ash/system/tray/tray_item_view.h"
 #include "base/macros.h"
 
 namespace ash {
 
+// Maximum count of notification shown by a number label. "+" icon is shown
+// instead if it exceeds this limit.
+constexpr size_t kTrayNotificationMaxCount = 9;
+
 // A notification counter view in UnifiedSystemTray button.
-class NotificationCounterView : public TrayItemView, public SessionObserver {
+class ASH_EXPORT NotificationCounterView : public TrayItemView,
+                                           public SessionObserver {
  public:
   explicit NotificationCounterView(Shelf* shelf);
   ~NotificationCounterView() override;
@@ -31,6 +37,8 @@
   // views::TrayItemView:
   const char* GetClassName() const override;
 
+  int count_for_display_for_testing() const { return count_for_display_; }
+
  private:
   // The type / number of the icon that is currently set to the image view.
   // 0 indicates no icon is drawn yet.
diff --git a/ash/system/unified/notification_counter_view_unittest.cc b/ash/system/unified/notification_counter_view_unittest.cc
new file mode 100644
index 0000000..b6e3bcb
--- /dev/null
+++ b/ash/system/unified/notification_counter_view_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/system/unified/notification_counter_view.h"
+
+#include "ash/media/media_notification_constants.h"
+#include "ash/public/cpp/ash_features.h"
+#include "ash/test/ash_test_base.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/public/cpp/notification.h"
+#include "ui/message_center/public/cpp/notification_types.h"
+#include "ui/message_center/public/cpp/notifier_id.h"
+#include "url/gurl.h"
+
+namespace ash {
+
+class NotificationCounterViewTest : public AshTestBase {
+ public:
+  NotificationCounterViewTest() = default;
+  NotificationCounterViewTest(const NotificationCounterViewTest&) = delete;
+  NotificationCounterViewTest& operator=(const NotificationCounterViewTest&) =
+      delete;
+  ~NotificationCounterViewTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    notification_counter_view_ =
+        std::make_unique<NotificationCounterView>(GetPrimaryShelf());
+  }
+
+  void TearDown() override {
+    notification_counter_view_.reset();
+    AshTestBase::TearDown();
+  }
+
+ protected:
+  void AddNotification(const std::string& notification_id,
+                       const std::string& app_id = "app") {
+    message_center::MessageCenter::Get()->AddNotification(
+        std::make_unique<message_center::Notification>(
+            message_center::NOTIFICATION_TYPE_BASE_FORMAT, notification_id,
+            base::UTF8ToUTF16("test_title"), base::UTF8ToUTF16("test message"),
+            gfx::Image(), /*display_source=*/base::string16(), GURL(),
+            message_center::NotifierId(
+                message_center::NotifierType::APPLICATION, app_id),
+            message_center::RichNotificationData(),
+            new message_center::NotificationDelegate()));
+  }
+
+  NotificationCounterView* notification_counter_view() {
+    return notification_counter_view_.get();
+  }
+
+ private:
+  std::unique_ptr<NotificationCounterView> notification_counter_view_;
+};
+
+TEST_F(NotificationCounterViewTest, CountForDisplay) {
+  // Not visible when count == 0.
+  notification_counter_view()->Update();
+  EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing());
+  EXPECT_FALSE(notification_counter_view()->GetVisible());
+
+  // Count is visible and updates between 1..max+1.
+  int max = static_cast<int>(kTrayNotificationMaxCount);
+  for (int i = 1; i <= max + 1; i++) {
+    AddNotification(base::NumberToString(i));
+    notification_counter_view()->Update();
+    EXPECT_EQ(i, notification_counter_view()->count_for_display_for_testing());
+    EXPECT_TRUE(notification_counter_view()->GetVisible());
+  }
+
+  // Count does not change after max+1.
+  AddNotification(base::NumberToString(max + 2));
+  notification_counter_view()->Update();
+  EXPECT_EQ(max + 1,
+            notification_counter_view()->count_for_display_for_testing());
+  EXPECT_TRUE(notification_counter_view()->GetVisible());
+}
+
+// Media notifications are not included when flag is set.
+TEST_F(NotificationCounterViewTest, MediaNotifications) {
+  notification_counter_view()->Update();
+  EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing());
+  AddNotification("1", kMediaSessionNotifierId);
+  {
+    // Counter should ignore media notifications when feature is enabled.
+    base::test::ScopedFeatureList features;
+    features.InitAndEnableFeature(features::kMediaNotificationsCounter);
+    notification_counter_view()->Update();
+    EXPECT_EQ(0, notification_counter_view()->count_for_display_for_testing());
+    EXPECT_FALSE(notification_counter_view()->GetVisible());
+  }
+  {
+    // Counter should show media notifications when feature is disabled.
+    base::test::ScopedFeatureList features;
+    features.InitAndDisableFeature(features::kMediaNotificationsCounter);
+    notification_counter_view()->Update();
+    EXPECT_EQ(1, notification_counter_view()->count_for_display_for_testing());
+    EXPECT_TRUE(notification_counter_view()->GetVisible());
+  }
+}
+
+}  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 6e82a458..44eb9eb6 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2043,9 +2043,18 @@
   if (is_posix && !is_mac && !is_ios) {
     sources += [
       "time/time_conversion_posix.cc",
+      "time/time_exploded_icu.cc",  # See note below.
       "time/time_exploded_posix.cc",
       "time/time_now_posix.cc",
     ]
+
+    # The ICU dependency is only needed on systems with a 32-bit time_t.
+    # However, that cannot be determined from build variables, like
+    # |current_cpu|, since some 32-bit systems have a 64-bit time_t (and vice
+    # versa). Thus, the dependency is taken here for all POSIX platforms and the
+    # compiler+linker should be able to easily detect when the ICU routines will
+    # not be called and delete them in the final linking.
+    deps += [ "//third_party/icu:icui18n" ]
   }
 
   if (is_posix && !is_mac && !is_ios && !is_nacl) {
diff --git a/base/time/time.cc b/base/time/time.cc
index 1b1a830..d224bd01 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -440,12 +440,20 @@
 }
 
 int64_t Time::ToRoundedDownMillisecondsSinceUnixEpoch() const {
-  // Adjust from Windows epoch (1601) to Unix epoch (1970).
-  const int64_t ms = (*this - UnixEpoch()).InMicroseconds();
+  constexpr int64_t kEpochOffsetMillis =
+      kTimeTToMicrosecondsOffset / kMicrosecondsPerMillisecond;
+  static_assert(kTimeTToMicrosecondsOffset % kMicrosecondsPerMillisecond == 0,
+                "assumption: no epoch offset sub-milliseconds");
 
-  // Floor rather than truncating.
-  return (ms >= 0) ? (ms / kMicrosecondsPerMillisecond)
-                   : ((ms + 1) / kMicrosecondsPerMillisecond - 1);
+  // Compute the milliseconds since UNIX epoch without the possibility of
+  // under/overflow. Round the result towards -infinity.
+  //
+  // If |us_| is negative and includes fractions of a millisecond, subtract one
+  // more to effect the round towards -infinity. C-style integer truncation
+  // takes care of all other cases.
+  const int64_t millis = us_ / kMicrosecondsPerMillisecond;
+  const int64_t submillis = us_ % kMicrosecondsPerMillisecond;
+  return millis - kEpochOffsetMillis - (submillis < 0);
 }
 
 std::ostream& operator<<(std::ostream& os, Time time) {
diff --git a/base/time/time.h b/base/time/time.h
index 69065def4..1eef31e 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -541,6 +541,9 @@
 // functions will return false if passed values outside these limits. The limits
 // are inclusive, meaning that the API should support all dates within a given
 // limit year.
+//
+// WARNING: These are not the same limits for the inverse functionality,
+// UTCExplode() and LocalExplode(). See method comments for further details.
 #if defined(OS_WIN)
   static constexpr int kExplodedMinYear = 1601;
   static constexpr int kExplodedMaxYear = 30827;
@@ -741,14 +744,16 @@
     return FromStringInternal(time_string, false, parsed_time);
   }
 
-  // Fills the given exploded structure with either the local time or UTC from
-  // this time structure (containing UTC).
-  void UTCExplode(Exploded* exploded) const {
-    return Explode(false, exploded);
-  }
-  void LocalExplode(Exploded* exploded) const {
-    return Explode(true, exploded);
-  }
+  // Fills the given |exploded| structure with either the local time or UTC from
+  // this Time instance. If the conversion cannot be made, the output will be
+  // assigned invalid values. Use Exploded::HasValidValues() to confirm a
+  // successful conversion.
+  //
+  // Y10K compliance: This method will successfully convert all Times that
+  // represent dates on/after the start of the year 1601 and on/before the start
+  // of the year 30828. Some platforms might convert over a wider input range.
+  void UTCExplode(Exploded* exploded) const { Explode(false, exploded); }
+  void LocalExplode(Exploded* exploded) const { Explode(true, exploded); }
 
   // The following two functions round down the time to the nearest day in
   // either UTC or local time. It will represent midnight on that day.
@@ -782,6 +787,16 @@
                            const Exploded& exploded,
                            Time* time) WARN_UNUSED_RESULT;
 
+  // Some platforms use the ICU library to provide To/FromExploded, when their
+  // native library implementations are insufficient in some way.
+  static void ExplodeUsingIcu(int64_t millis_since_unix_epoch,
+                              bool is_local,
+                              Exploded* exploded);
+  static bool FromExplodedUsingIcu(bool is_local,
+                                   const Exploded& exploded,
+                                   int64_t* millis_since_unix_epoch)
+      WARN_UNUSED_RESULT;
+
   // Rounds down the time to the nearest day in either local time
   // |is_local = true| or UTC |is_local = false|.
   Time Midnight(bool is_local) const;
diff --git a/base/time/time_exploded_icu.cc b/base/time/time_exploded_icu.cc
index 41832e53..6690bbea 100644
--- a/base/time/time_exploded_icu.cc
+++ b/base/time/time_exploded_icu.cc
@@ -8,15 +8,12 @@
 
 #include "base/check.h"
 #include "base/memory/ptr_util.h"
+#include "build/build_config.h"
 #include "third_party/icu/source/i18n/unicode/calendar.h"
 #include "third_party/icu/source/i18n/unicode/timezone.h"
 
 namespace base {
 
-static_assert(
-    sizeof(Time::Exploded::year) == sizeof(int32_t),
-    "The sizes of Time::Exploded members and ICU date fields do not match.");
-
 namespace {
 
 // Returns a new icu::Calendar instance for the local time zone if |is_local|
@@ -32,45 +29,87 @@
   return calendar;
 }
 
-}  // namespace
+// Explodes the |millis_since_unix_epoch| using an icu::Calendar, and returns
+// true if the conversion was successful.
+bool ExplodeUsingIcuCalendar(int64_t millis_since_unix_epoch,
+                             bool is_local,
+                             Time::Exploded* exploded) {
+  // ICU's year calculation is wrong for years too far in the past (though
+  // other fields seem to be correct). Given that the Time::Explode() for
+  // Windows only works for values on/after 1601-01-01 00:00:00 UTC, just use
+  // that as a reasonable lower-bound here as well.
+  constexpr int64_t kInputLowerBound =
+      -Time::kTimeTToMicrosecondsOffset / Time::kMicrosecondsPerMillisecond;
+  static_assert(
+      Time::kTimeTToMicrosecondsOffset % Time::kMicrosecondsPerMillisecond == 0,
+      "assumption: no epoch offset sub-milliseconds");
 
-void Time::Explode(bool is_local, Exploded* exploded) const {
+  // The input to icu::Calendar is a double-typed value. To ensure no loss of
+  // precision when converting int64_t to double, an upper-bound must also be
+  // imposed.
+  static_assert(std::numeric_limits<double>::radix == 2, "");
+  constexpr int64_t kInputUpperBound = uint64_t{1}
+                                       << std::numeric_limits<double>::digits;
+
+  if (millis_since_unix_epoch < kInputLowerBound ||
+      millis_since_unix_epoch > kInputUpperBound) {
+    return false;
+  }
+
   std::unique_ptr<icu::Calendar> calendar = CreateCalendar(is_local);
-
   UErrorCode status = U_ZERO_ERROR;
-  calendar->setTime(ToRoundedDownMillisecondsSinceUnixEpoch(), status);
-  DCHECK(U_SUCCESS(status));
+  calendar->setTime(millis_since_unix_epoch, status);
+  if (!U_SUCCESS(status))
+    return false;
 
+  using CalendarField = decltype(calendar->get(UCAL_YEAR, status));
+  static_assert(sizeof(Time::Exploded::year) >= sizeof(CalendarField),
+                "Time::Exploded members are not large enough to hold ICU "
+                "calendar fields.");
+
+  bool got_all_fields = true;
   exploded->year = calendar->get(UCAL_YEAR, status);
-  DCHECK(U_SUCCESS(status));
-
+  got_all_fields &= !!U_SUCCESS(status);
   // ICU's UCalendarMonths is 0-based. E.g., 0 for January.
   exploded->month = calendar->get(UCAL_MONTH, status) + 1;
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   // ICU's UCalendarDaysOfWeek is 1-based. E.g., 1 for Sunday.
   exploded->day_of_week = calendar->get(UCAL_DAY_OF_WEEK, status) - 1;
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   exploded->day_of_month = calendar->get(UCAL_DAY_OF_MONTH, status);
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   exploded->hour = calendar->get(UCAL_HOUR_OF_DAY, status);
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   exploded->minute = calendar->get(UCAL_MINUTE, status);
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   exploded->second = calendar->get(UCAL_SECOND, status);
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
   exploded->millisecond = calendar->get(UCAL_MILLISECOND, status);
-  DCHECK(U_SUCCESS(status));
+  got_all_fields &= !!U_SUCCESS(status);
+  return got_all_fields;
+}
+
+}  // namespace
+
+// static
+void Time::ExplodeUsingIcu(int64_t millis_since_unix_epoch,
+                           bool is_local,
+                           Exploded* exploded) {
+  if (!ExplodeUsingIcuCalendar(millis_since_unix_epoch, is_local, exploded)) {
+    // Error: Return an invalid Exploded.
+    *exploded = {};
+  }
 }
 
 // static
-bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+bool Time::FromExplodedUsingIcu(bool is_local,
+                                const Exploded& exploded,
+                                int64_t* millis_since_unix_epoch) {
   // ICU's UCalendarMonths is 0-based. E.g., 0 for January.
   CheckedNumeric<int> month = exploded.month;
   month--;
-  if (!month.IsValid()) {
-    *time = Time(0);
+  if (!month.IsValid())
     return false;
-  }
 
   std::unique_ptr<icu::Calendar> calendar = CreateCalendar(is_local);
 
@@ -85,12 +124,29 @@
 
   UErrorCode status = U_ZERO_ERROR;
   UDate date = calendar->getTime(status);
-  if (U_FAILURE(status)) {
-    *time = Time(0);
+  if (U_FAILURE(status))
     return false;
-  }
 
-  return FromMillisecondsSinceUnixEpoch(date, time);
+  *millis_since_unix_epoch = saturated_cast<int64_t>(date);
+  return true;
 }
 
+#if defined(OS_FUCHSIA)
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  return ExplodeUsingIcu(ToRoundedDownMillisecondsSinceUnixEpoch(), is_local,
+                         exploded);
+}
+
+// static
+bool Time::FromExploded(bool is_local, const Exploded& exploded, Time* time) {
+  int64_t millis_since_unix_epoch;
+  if (FromExplodedUsingIcu(is_local, exploded, &millis_since_unix_epoch))
+    return FromMillisecondsSinceUnixEpoch(millis_since_unix_epoch, time);
+  *time = Time(0);
+  return false;
+}
+
+#endif  // defined(OS_FUCHSIA)
+
 }  // namespace base
diff --git a/base/time/time_exploded_posix.cc b/base/time/time_exploded_posix.cc
index d0115eb..4d8dbe01 100644
--- a/base/time/time_exploded_posix.cc
+++ b/base/time/time_exploded_posix.cc
@@ -14,33 +14,29 @@
 
 #include <limits>
 
+#include "base/no_destructor.h"
 #include "base/numerics/safe_math.h"
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
 
-#if defined(OS_ANDROID)
-#include "base/os_compat_android.h"
-#elif defined(OS_NACL)
+#if defined(OS_NACL)
 #include "base/os_compat_nacl.h"
 #endif
 
-#if defined(OS_APPLE)
-static_assert(sizeof(time_t) >= 8, "Y2038 problem!");
-#endif
-
 namespace {
 
 // This prevents a crash on traversing the environment global and looking up
 // the 'TZ' variable in libc. See: crbug.com/390567.
 base::Lock* GetSysTimeToTimeStructLock() {
-  static auto* lock = new base::Lock();
-  return lock;
+  static base::NoDestructor<base::Lock> lock;
+  return lock.get();
 }
 
 // Define a system-specific SysTime that wraps either to a time_t or
 // a time64_t depending on the host system, and associated convertion.
 // See crbug.com/162007
 #if defined(OS_ANDROID) && !defined(__LP64__)
+
 typedef time64_t SysTime;
 
 SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
@@ -58,7 +54,9 @@
   else
     gmtime64_r(&t, timestruct);
 }
+
 #elif defined(OS_AIX)
+
 // The function timegm is not available on AIX.
 time_t aix_timegm(struct tm* tm) {
   time_t ret;
@@ -99,7 +97,8 @@
     gmtime_r(&t, timestruct);
 }
 
-#else
+#else  // MacOS (and iOS 64-bit), Linux/ChromeOS, or any other POSIX-compliant.
+
 typedef time_t SysTime;
 
 SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
@@ -114,6 +113,7 @@
   else
     gmtime_r(&t, timestruct);
 }
+
 #endif  // defined(OS_ANDROID) && !defined(__LP64__)
 
 }  // namespace
@@ -121,24 +121,25 @@
 namespace base {
 
 void Time::Explode(bool is_local, Exploded* exploded) const {
-  // The following values are all rounded towards -infinity.
-  int64_t milliseconds = ToRoundedDownMillisecondsSinceUnixEpoch();
-  SysTime seconds;       // Seconds since epoch.
-  int millisecond;       // Exploded millisecond value (0-999).
+  const int64_t millis_since_unix_epoch =
+      ToRoundedDownMillisecondsSinceUnixEpoch();
 
-  // If the microseconds were negative, the rounded down milliseconds will also
-  // be negative. For example, -1 us becomes -1 ms.
-  if (milliseconds >= 0) {
-    // Rounding towards -infinity <=> rounding towards 0, in this case.
-    seconds = milliseconds / kMillisecondsPerSecond;
-    millisecond = milliseconds % kMillisecondsPerSecond;
-  } else {
-    // Round these *down* (towards -infinity).
-    seconds = (milliseconds + 1) / kMillisecondsPerSecond - 1;
-    // Make this nonnegative (and between 0 and 999 inclusive).
-    millisecond = milliseconds % kMillisecondsPerSecond;
-    if (millisecond < 0)
-      millisecond += kMillisecondsPerSecond;
+  // For systems with a Y2038 problem, use ICU as the Explode() implementation.
+  if (sizeof(SysTime) < 8) {
+    ExplodeUsingIcu(millis_since_unix_epoch, is_local, exploded);
+    return;
+  }
+
+  // Split the |millis_since_unix_epoch| into separate seconds and millisecond
+  // components because the platform calendar-explode operates at one-second
+  // granularity.
+  SysTime seconds = millis_since_unix_epoch / Time::kMillisecondsPerSecond;
+  int64_t millisecond = millis_since_unix_epoch % Time::kMillisecondsPerSecond;
+  if (millisecond < 0) {
+    // Make the the |millisecond| component positive, within the range [0,999],
+    // by transferring 1000 ms from |seconds|.
+    --seconds;
+    millisecond += Time::kMillisecondsPerSecond;
   }
 
   struct tm timestruct;
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 59e06f2..d17b46ec 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -958,6 +958,134 @@
 }
 #endif  // OS_ANDROID
 
+// Regression test for https://crbug.com/1104442
+TEST_F(TimeTest, Explode_Y10KCompliance) {
+  constexpr int kDaysPerYear = 365;
+  constexpr int64_t kHalfYearInMicros =
+      TimeDelta::FromDays(kDaysPerYear / 2).InMicroseconds();
+
+  // The Y2038 issue occurs when a 32-bit signed integer overflows.
+  constexpr int64_t kYear2038MicrosOffset =
+      Time::kTimeTToMicrosecondsOffset +
+      (std::numeric_limits<int32_t>::max() * Time::kMicrosecondsPerSecond);
+
+  // 1 March 10000 at noon.
+  constexpr int64_t kYear10000YearsOffset = 10000 - 1970;
+  constexpr int kExtraLeapDaysOverThoseYears = 1947;
+  constexpr int kDaysFromJanToMar10000 = 31 + 29;
+  constexpr int64_t kMarch10000MicrosOffset =
+      Time::kTimeTToMicrosecondsOffset +
+      TimeDelta::FromDays(kYear10000YearsOffset * kDaysPerYear +
+                          kExtraLeapDaysOverThoseYears + kDaysFromJanToMar10000)
+          .InMicroseconds() +
+      TimeDelta::FromHours(12).InMicroseconds();
+
+  // Windows uses a 64-bit signed integer type that reperesents the number of
+  // 1/10 microsecond ticks.
+  constexpr int64_t kWindowsMaxMicrosOffset =
+      std::numeric_limits<int64_t>::max() / 10;
+
+  // ICU's Calendar API uses double values. Thus, the maximum supported value is
+  // the maximum integer that can be represented by a double.
+  static_assert(std::numeric_limits<double>::radix == 2, "");
+  constexpr int64_t kMaxIntegerAsDoubleMillis =
+      int64_t{1} << std::numeric_limits<double>::digits;
+  constexpr int64_t kIcuMaxMicrosOffset =
+      Time::kTimeTToMicrosecondsOffset +
+      (kMaxIntegerAsDoubleMillis * Time::kMicrosecondsPerMillisecond + 999);
+
+  const auto make_time = [](int64_t micros) {
+    return Time::FromDeltaSinceWindowsEpoch(
+        TimeDelta::FromMicroseconds(micros));
+  };
+
+  const struct TestCase {
+    Time time;
+    Time::Exploded expected;
+  } kTestCases[] = {
+      // A very long time ago.
+      {Time::Min(), Time::Exploded{-290677, 12, 4, 23, 19, 59, 5, 224}},
+
+      // Before/On/After 1 Jan 1601.
+      {make_time(-kHalfYearInMicros),
+       Time::Exploded{1600, 7, 1, 3, 0, 0, 0, 0}},
+      {make_time(0), Time::Exploded{1601, 1, 1, 1, 0, 0, 0, 0}},
+      {make_time(kHalfYearInMicros), Time::Exploded{1601, 7, 1, 2, 0, 0, 0, 0}},
+
+      // Before/On/After 1 Jan 1970.
+      {make_time(Time::kTimeTToMicrosecondsOffset - kHalfYearInMicros),
+       Time::Exploded{1969, 7, 4, 3, 0, 0, 0, 0}},
+      {make_time(Time::kTimeTToMicrosecondsOffset),
+       Time::Exploded{1970, 1, 4, 1, 0, 0, 0, 0}},
+      {make_time(Time::kTimeTToMicrosecondsOffset + kHalfYearInMicros),
+       Time::Exploded{1970, 7, 4, 2, 0, 0, 0, 0}},
+
+      // Before/On/After 19 January 2038.
+      {make_time(kYear2038MicrosOffset - kHalfYearInMicros),
+       Time::Exploded{2037, 7, 2, 21, 3, 14, 7, 0}},
+      {make_time(kYear2038MicrosOffset),
+       Time::Exploded{2038, 1, 2, 19, 3, 14, 7, 0}},
+      {make_time(kYear2038MicrosOffset + kHalfYearInMicros),
+       Time::Exploded{2038, 7, 2, 20, 3, 14, 7, 0}},
+
+      // Before/On/After 1 March 10000 at noon.
+      {make_time(kMarch10000MicrosOffset - kHalfYearInMicros),
+       Time::Exploded{9999, 9, 3, 1, 12, 0, 0, 0}},
+      {make_time(kMarch10000MicrosOffset),
+       Time::Exploded{10000, 3, 3, 1, 12, 0, 0, 0}},
+      {make_time(kMarch10000MicrosOffset + kHalfYearInMicros),
+       Time::Exploded{10000, 8, 3, 30, 12, 0, 0, 0}},
+
+      // Before/On/After Windows Max (14 September 30828).
+      {make_time(kWindowsMaxMicrosOffset - kHalfYearInMicros),
+       Time::Exploded{30828, 3, 4, 16, 2, 48, 5, 477}},
+      {make_time(kWindowsMaxMicrosOffset),
+       Time::Exploded{30828, 9, 4, 14, 2, 48, 5, 477}},
+      {make_time(kWindowsMaxMicrosOffset + kHalfYearInMicros),
+       Time::Exploded{30829, 3, 4, 15, 2, 48, 5, 477}},
+
+      // Before/On/After ICU Max.
+      {make_time(kIcuMaxMicrosOffset - kHalfYearInMicros),
+       Time::Exploded{287396, 4, 3, 13, 8, 59, 0, 992}},
+      {make_time(kIcuMaxMicrosOffset),
+       Time::Exploded{287396, 10, 3, 12, 8, 59, 0, 992}},
+      {make_time(kIcuMaxMicrosOffset + kHalfYearInMicros),
+       Time::Exploded{287397, 4, 3, 12, 8, 59, 0, 992}},
+
+      // A very long time from now.
+      {Time::Max(), Time::Exploded{293878, 1, 4, 10, 4, 0, 54, 775}},
+  };
+
+  for (const TestCase& test_case : kTestCases) {
+    SCOPED_TRACE(testing::Message() << "Time: " << test_case.time);
+
+    Time::Exploded exploded = {};
+    test_case.time.UTCExplode(&exploded);
+
+    // Confirm the implementation provides a correct conversion for all inputs
+    // within the guaranteed range (as discussed in the header comments). If an
+    // implementation provides a result for inputs outside the guaranteed range,
+    // the result must still be correct.
+    if (exploded.HasValidValues()) {
+      EXPECT_EQ(test_case.expected.year, exploded.year);
+      EXPECT_EQ(test_case.expected.month, exploded.month);
+      EXPECT_EQ(test_case.expected.day_of_week, exploded.day_of_week);
+      EXPECT_EQ(test_case.expected.day_of_month, exploded.day_of_month);
+      EXPECT_EQ(test_case.expected.hour, exploded.hour);
+      EXPECT_EQ(test_case.expected.minute, exploded.minute);
+      EXPECT_EQ(test_case.expected.second, exploded.second);
+      EXPECT_EQ(test_case.expected.millisecond, exploded.millisecond);
+    } else {
+      // The implementation could not provide a conversion. That is only allowed
+      // for inputs outside the guaranteed range.
+      const bool is_in_range =
+          test_case.time >= make_time(0) &&
+          test_case.time <= make_time(kWindowsMaxMicrosOffset);
+      EXPECT_FALSE(is_in_range);
+    }
+  }
+}
+
 TEST_F(TimeTest, FromExploded_MinMax) {
   Time::Exploded exploded = {0};
   exploded.month = 1;
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
index bc2b4f6..36ab0f65 100644
--- a/base/time/time_win.cc
+++ b/base/time/time_win.cc
@@ -62,13 +62,17 @@
   return bit_cast<int64_t, FILETIME>(ft) / 10;
 }
 
-void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
-  DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
-      "representable in FILETIME";
+bool CanConvertToFileTime(int64_t us) {
+  return us >= 0 && us <= (std::numeric_limits<int64_t>::max() / 10);
+}
+
+FILETIME MicrosecondsToFileTime(int64_t us) {
+  DCHECK(CanConvertToFileTime(us)) << "Out-of-range: Cannot convert " << us
+                                   << " microseconds to FILETIME units.";
 
   // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will
   // handle alignment problems. This only works on little-endian machines.
-  *ft = bit_cast<FILETIME, int64_t>(us * 10);
+  return bit_cast<FILETIME, int64_t>(us * 10);
 }
 
 int64_t CurrentWallclockMicroseconds() {
@@ -235,9 +239,7 @@
     result.dwLowDateTime = std::numeric_limits<DWORD>::max();
     return result;
   }
-  FILETIME utc_ft;
-  MicrosecondsToFileTime(us_, &utc_ft);
-  return utc_ft;
+  return MicrosecondsToFileTime(us_);
 }
 
 // static
@@ -348,15 +350,13 @@
 }
 
 void Time::Explode(bool is_local, Exploded* exploded) const {
-  if (us_ < 0LL) {
+  if (!CanConvertToFileTime(us_)) {
     // We are not able to convert it to FILETIME.
     ZeroMemory(exploded, sizeof(*exploded));
     return;
   }
 
-  // FILETIME in UTC.
-  FILETIME utc_ft;
-  MicrosecondsToFileTime(us_, &utc_ft);
+  const FILETIME utc_ft = MicrosecondsToFileTime(us_);
 
   // FILETIME in local time if necessary.
   bool success = true;
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
index 0b82875..02298051 100644
--- a/build/android/gyp/util/build_utils.py
+++ b/build/android/gyp/util/build_utils.py
@@ -38,9 +38,6 @@
 RT_JAR_PATH = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'jdk', 'extras',
                            'java_8', 'jre', 'lib', 'rt.jar')
 
-# TODO(agrieve): Remove once safe to do so.
-JAVA_PATH = os.path.join(JAVA_HOME, 'bin', 'java')
-
 try:
   string_types = basestring
 except NameError:
diff --git a/build/args/headless.gn b/build/args/headless.gn
index 4c2e8d9ff..6936b258 100644
--- a/build/args/headless.gn
+++ b/build/args/headless.gn
@@ -45,6 +45,3 @@
 use_glib = false
 use_gtk = false
 use_pangocairo = false
-
-# TODO(1096425): Remove this once use_x11 goes away.
-use_x11 = false
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 063d338..5bdd159d8 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -18,19 +18,11 @@
 # of //build/config/BUILDCONFIG.gn.
 
 import("//build/config/chromecast_build.gni")
-import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Indicates if Ozone is enabled. Ozone is a low-level library layer for Linux
-  # that does not require X11.
-  use_ozone =
-      is_chromeos || (is_chromecast && !is_android) || is_fuchsia || is_linux
-
-  # Indicates if the UI toolkit depends on X11.
-  # Enabled by default. Can be disabled if Ozone only build is required and
-  # vice-versa.
-  use_x11 =
-      is_linux && !is_chromecast && !is_chromeos && !chromeos_is_browser_only
+  # that does not require X11. Enabling this feature disables use of x11.
+  use_ozone = is_chromeos || (is_chromecast && !is_android) || is_fuchsia
 
   # Indicates if Aura is enabled. Aura is a low-level windowing library, sort
   # of a replacement for GDI or GTK.
@@ -45,6 +37,13 @@
   use_glib = is_desktop_linux && !is_chromecast
 }
 
+# Additional dependent variables -----------------------------------------------
+#
+# These variables depend on other variables and can't be set externally.
+
+# Indicates if the UI toolkit depends on X11.
+use_x11 = is_linux && !use_ozone
+
 # Make sure glib is not used if building for ChromeOS/Chromecast
 assert(!use_glib || (is_linux && !is_chromeos && !is_chromecast))
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 7e1189f..da22f50 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -679,6 +679,7 @@
     "metrics/compositor_frame_reporter_unittest.cc",
     "metrics/compositor_frame_reporting_controller_unittest.cc",
     "metrics/compositor_timing_history_unittest.cc",
+    "metrics/dropped_frame_counter_unittest.cc",
     "metrics/events_metrics_manager_unittest.cc",
     "metrics/frame_sequence_metrics_unittest.cc",
     "metrics/frame_sequence_tracker_unittest.cc",
diff --git a/cc/metrics/compositor_frame_reporter.cc b/cc/metrics/compositor_frame_reporter.cc
index afe42621..5d7a75b 100644
--- a/cc/metrics/compositor_frame_reporter.cc
+++ b/cc/metrics/compositor_frame_reporter.cc
@@ -300,11 +300,13 @@
     const ActiveTrackers& active_trackers,
     const viz::BeginFrameArgs& args,
     LatencyUkmReporter* latency_ukm_reporter,
-    bool should_report_metrics)
+    bool should_report_metrics,
+    SmoothThread smooth_thread)
     : should_report_metrics_(should_report_metrics),
       args_(args),
       active_trackers_(active_trackers),
-      latency_ukm_reporter_(latency_ukm_reporter) {}
+      latency_ukm_reporter_(latency_ukm_reporter),
+      smooth_thread_(smooth_thread) {}
 
 std::unique_ptr<CompositorFrameReporter>
 CompositorFrameReporter::CopyReporterAtBeginImplStage() const {
@@ -315,7 +317,8 @@
     return nullptr;
   }
   auto new_reporter = std::make_unique<CompositorFrameReporter>(
-      active_trackers_, args_, latency_ukm_reporter_, should_report_metrics_);
+      active_trackers_, args_, latency_ukm_reporter_, should_report_metrics_,
+      smooth_thread_);
   new_reporter->did_finish_impl_frame_ = did_finish_impl_frame_;
   new_reporter->impl_frame_finish_time_ = impl_frame_finish_time_;
   new_reporter->main_frame_abort_time_ = main_frame_abort_time_;
@@ -484,6 +487,9 @@
       else
         dropped_frame_counter_->AddGoodFrame();
     }
+
+    if (IsDroppedFrameAffectingSmoothness())
+      dropped_frame_counter_->AddDroppedFrameAffectingSmoothness();
   }
 }
 
@@ -1033,4 +1039,25 @@
   return tick_clock_->NowTicks();
 }
 
+bool CompositorFrameReporter::IsDroppedFrameAffectingSmoothness() const {
+  // If the frame was not shown, then it hurt smoothness only if either of the
+  // threads is affecting smoothness (e.g. running an animation, scroll, pinch,
+  // etc.).
+  if (TestReportType(FrameReportType::kDroppedFrame)) {
+    return smooth_thread_ != SmoothThread::kSmoothNone;
+  }
+
+  // If the frame was shown, but included only partial updates, then it hurt
+  // smoothness only if the main-thread is affecting smoothness (e.g. running an
+  // animation, or scroll etc.).
+  if (has_partial_update_) {
+    return smooth_thread_ == SmoothThread::kSmoothMain ||
+           smooth_thread_ == SmoothThread::kSmoothBoth;
+  }
+
+  // If the frame was shown, and did not include partial updates, then this
+  // frame did not hurt smoothness.
+  return false;
+}
+
 }  // namespace cc
diff --git a/cc/metrics/compositor_frame_reporter.h b/cc/metrics/compositor_frame_reporter.h
index 85344d2..005d8c74 100644
--- a/cc/metrics/compositor_frame_reporter.h
+++ b/cc/metrics/compositor_frame_reporter.h
@@ -7,13 +7,13 @@
 
 #include <bitset>
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
 #include "base/optional.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
-#include "cc/base/base_export.h"
 #include "cc/cc_export.h"
 #include "cc/metrics/begin_main_frame_metrics.h"
 #include "cc/metrics/event_metrics.h"
@@ -133,13 +133,21 @@
     ~StageData();
   };
 
+  enum SmoothThread {
+    kSmoothNone,
+    kSmoothCompositor,
+    kSmoothMain,
+    kSmoothBoth
+  };
+
   using ActiveTrackers =
       std::bitset<static_cast<size_t>(FrameSequenceTrackerType::kMaxType)>;
 
   CompositorFrameReporter(const ActiveTrackers& active_trackers,
                           const viz::BeginFrameArgs& args,
                           LatencyUkmReporter* latency_ukm_reporter,
-                          bool should_report_metrics);
+                          bool should_report_metrics,
+                          SmoothThread smooth_thread);
   ~CompositorFrameReporter();
 
   CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
@@ -245,6 +253,8 @@
 
   base::TimeTicks Now() const;
 
+  bool IsDroppedFrameAffectingSmoothness() const;
+
   const bool should_report_metrics_;
   const viz::BeginFrameArgs args_;
 
@@ -296,6 +306,8 @@
 
   DroppedFrameCounter* dropped_frame_counter_ = nullptr;
   bool has_partial_update_ = false;
+
+  const SmoothThread smooth_thread_;
 };
 
 }  // namespace cc
diff --git a/cc/metrics/compositor_frame_reporter_unittest.cc b/cc/metrics/compositor_frame_reporter_unittest.cc
index dd0bde4..695e441ef 100644
--- a/cc/metrics/compositor_frame_reporter_unittest.cc
+++ b/cc/metrics/compositor_frame_reporter_unittest.cc
@@ -32,7 +32,8 @@
             CompositorFrameReporter::ActiveTrackers(),
             viz::BeginFrameArgs(),
             nullptr,
-            /*should_report_metrics=*/true)) {
+            /*should_report_metrics=*/true,
+            CompositorFrameReporter::SmoothThread::kSmoothBoth)) {
     pipeline_reporter_->set_tick_clock(&test_tick_clock_);
     AdvanceNowByMs(1);
   }
diff --git a/cc/metrics/compositor_frame_reporting_controller.cc b/cc/metrics/compositor_frame_reporting_controller.cc
index b19d869..4190f01 100644
--- a/cc/metrics/compositor_frame_reporting_controller.cc
+++ b/cc/metrics/compositor_frame_reporting_controller.cc
@@ -13,6 +13,7 @@
 
 namespace cc {
 namespace {
+using SmoothThread = CompositorFrameReporter::SmoothThread;
 using StageType = CompositorFrameReporter::StageType;
 using FrameTerminationStatus = CompositorFrameReporter::FrameTerminationStatus;
 }  // namespace
@@ -69,7 +70,7 @@
   }
   auto reporter = std::make_unique<CompositorFrameReporter>(
       active_trackers_, args, latency_ukm_reporter_.get(),
-      should_report_metrics_);
+      should_report_metrics_, GetSmoothThread());
   reporter->set_tick_clock(tick_clock_);
   reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
                        begin_time);
@@ -96,7 +97,7 @@
     // deadline yet). So will start a new reporter at BeginMainFrame.
     auto reporter = std::make_unique<CompositorFrameReporter>(
         active_trackers_, args, latency_ukm_reporter_.get(),
-        should_report_metrics_);
+        should_report_metrics_, GetSmoothThread());
     reporter->set_tick_clock(tick_clock_);
     reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
     reporter->SetDroppedFrameCounter(dropped_frame_counter_);
@@ -347,6 +348,17 @@
   active_trackers_.reset(static_cast<size_t>(type));
 }
 
+void CompositorFrameReportingController::SetThreadAffectsSmoothness(
+    FrameSequenceMetrics::ThreadType thread_type,
+    bool affects_smoothness) {
+  if (thread_type == FrameSequenceMetrics::ThreadType::kCompositor) {
+    is_compositor_thread_driving_smoothness_ = affects_smoothness;
+  } else {
+    DCHECK_EQ(thread_type, FrameSequenceMetrics::ThreadType::kMain);
+    is_main_thread_driving_smoothness_ = affects_smoothness;
+  }
+}
+
 void CompositorFrameReportingController::AdvanceReporterStage(
     PipelineStage start,
     PipelineStage target) {
@@ -401,4 +413,16 @@
   latency_ukm_reporter_->set_ukm_manager(manager);
 }
 
+CompositorFrameReporter::SmoothThread
+CompositorFrameReportingController::GetSmoothThread() const {
+  if (is_main_thread_driving_smoothness_) {
+    return is_compositor_thread_driving_smoothness_ ? SmoothThread::kSmoothBoth
+                                                    : SmoothThread::kSmoothMain;
+  }
+
+  return is_compositor_thread_driving_smoothness_
+             ? SmoothThread::kSmoothCompositor
+             : SmoothThread::kSmoothNone;
+}
+
 }  // namespace cc
diff --git a/cc/metrics/compositor_frame_reporting_controller.h b/cc/metrics/compositor_frame_reporting_controller.h
index 2659e92..714c60f 100644
--- a/cc/metrics/compositor_frame_reporting_controller.h
+++ b/cc/metrics/compositor_frame_reporting_controller.h
@@ -76,8 +76,11 @@
 
   void SetUkmManager(UkmManager* manager);
 
-  virtual void AddActiveTracker(FrameSequenceTrackerType type);
-  virtual void RemoveActiveTracker(FrameSequenceTrackerType type);
+  void AddActiveTracker(FrameSequenceTrackerType type);
+  void RemoveActiveTracker(FrameSequenceTrackerType type);
+
+  void SetThreadAffectsSmoothness(FrameSequenceMetrics::ThreadType thread_type,
+                                  bool affects_smoothness);
 
   void set_tick_clock(const base::TickClock* tick_clock) {
     DCHECK(tick_clock);
@@ -113,6 +116,7 @@
   bool CanSubmitMainFrame(const viz::BeginFrameId& id) const;
   std::unique_ptr<CompositorFrameReporter> RestoreReporterAtBeginImpl(
       const viz::BeginFrameId& id);
+  CompositorFrameReporter::SmoothThread GetSmoothThread() const;
 
   const bool should_report_metrics_;
   viz::BeginFrameId last_submitted_frame_id_;
@@ -120,6 +124,9 @@
   bool next_activate_has_invalidation_ = false;
   CompositorFrameReporter::ActiveTrackers active_trackers_;
 
+  bool is_compositor_thread_driving_smoothness_ = false;
+  bool is_main_thread_driving_smoothness_ = false;
+
   // The latency reporter passed to each CompositorFrameReporter. Owned here
   // because it must be common among all reporters.
   // DO NOT reorder this line and the ones below. The latency_ukm_reporter_ must
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index 315c94118..b0b37e4 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -41,10 +41,15 @@
   ++total_dropped_;
 }
 
+void DroppedFrameCounter::AddDroppedFrameAffectingSmoothness() {
+  ++total_smoothness_dropped_;
+}
+
 void DroppedFrameCounter::Reset() {
   total_frames_ = 0;
   total_partial_ = 0;
   total_dropped_ = 0;
+  total_smoothness_dropped_ = 0;
   ring_buffer_.Clear();
 }
 
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h
index 9410d6d2..ddc4e056 100644
--- a/cc/metrics/dropped_frame_counter.h
+++ b/cc/metrics/dropped_frame_counter.h
@@ -10,12 +10,13 @@
 #include <memory>
 
 #include "base/containers/ring_buffer.h"
+#include "cc/cc_export.h"
 
 namespace cc {
 
 // This class maintains a counter for produced/dropped frames, and can be used
 // to estimate the recent throughput.
-class DroppedFrameCounter {
+class CC_EXPORT DroppedFrameCounter {
  public:
   enum FrameState {
     kFrameStateDropped,
@@ -32,6 +33,7 @@
   size_t total_frames() const { return total_frames_; }
   size_t total_compositor_dropped() const { return total_dropped_; }
   size_t total_main_dropped() const { return total_partial_; }
+  size_t total_smoothness_dropped() const { return total_smoothness_dropped_; }
 
   uint32_t GetAverageThroughput() const;
 
@@ -43,6 +45,8 @@
   void AddPartialFrame();
   void AddDroppedFrame();
 
+  void AddDroppedFrameAffectingSmoothness();
+
   void Reset();
 
  private:
@@ -50,6 +54,7 @@
   size_t total_frames_ = 0;
   size_t total_partial_ = 0;
   size_t total_dropped_ = 0;
+  size_t total_smoothness_dropped_ = 0;
 };
 
 }  // namespace cc
diff --git a/cc/metrics/dropped_frame_counter_unittest.cc b/cc/metrics/dropped_frame_counter_unittest.cc
new file mode 100644
index 0000000..bfaf647
--- /dev/null
+++ b/cc/metrics/dropped_frame_counter_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/metrics/dropped_frame_counter.h"
+
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "cc/animation/animation_host.h"
+#include "cc/test/layer_tree_test.h"
+
+namespace cc {
+namespace {
+
+class DroppedFrameCounterTestBase : public LayerTreeTest {
+ public:
+  DroppedFrameCounterTestBase() = default;
+  ~DroppedFrameCounterTestBase() override = default;
+
+  virtual void SetUpTestConfigAndExpectations() = 0;
+
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->commit_to_active_tree = false;
+  }
+
+  void RunTest(CompositorMode mode) override {
+    SetUpTestConfigAndExpectations();
+    LayerTreeTest::RunTest(mode);
+  }
+
+  void BeginTest() override {
+    ASSERT_GT(config_.animation_frames, 0u);
+
+    // Start with requesting main-frames.
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void AfterTest() override {
+    EXPECT_GE(total_frames_, config_.animation_frames);
+    // It is possible to drop even more frame than what the test expects (e.g.
+    // in slower machines, slower builds such as asan/tsan builds, etc.), since
+    // the test does not strictly control both threads and deadlines. Therefore,
+    // it is not possible to check for strict equality here.
+    EXPECT_LE(expect_.min_dropped_main, dropped_main_);
+    EXPECT_LE(expect_.min_dropped_compositor, dropped_compositor_);
+    EXPECT_LE(expect_.min_dropped_smoothness, dropped_smoothness_);
+  }
+
+  // Compositor thread function overrides:
+  void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
+                                  const viz::BeginFrameArgs& args) override {
+    // Request a re-draw, and set a non-empty damage region (otherwise the
+    // draw is aborted with 'no damage').
+    host_impl->SetNeedsRedraw();
+    host_impl->SetViewportDamage(gfx::Rect(0, 0, 10, 20));
+
+    // Request update from the main-thread too.
+    PostSetNeedsCommitToMainThread();
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    // If the main-thread is blocked, then unblock it once the compositor thread
+    // has already drawn a frame.
+    base::WaitableEvent* wait = nullptr;
+    {
+      base::AutoLock lock(wait_lock_);
+      wait = wait_;
+    }
+
+    if (wait) {
+      wait->Signal();
+    }
+  }
+
+  void DidReceivePresentationTimeOnThread(
+      LayerTreeHostImpl* host_impl,
+      uint32_t frame_token,
+      const gfx::PresentationFeedback& feedback) override {
+    ++presented_frames_;
+    if (presented_frames_ < config_.animation_frames)
+      return;
+
+    auto* dropped_frame_counter = host_impl->dropped_frame_counter();
+    DCHECK(dropped_frame_counter);
+
+    total_frames_ = dropped_frame_counter->total_frames();
+    dropped_main_ = dropped_frame_counter->total_main_dropped();
+    dropped_compositor_ = dropped_frame_counter->total_compositor_dropped();
+    dropped_smoothness_ = dropped_frame_counter->total_smoothness_dropped();
+    EndTest();
+  }
+
+  // Main-thread function overrides:
+  void BeginMainFrame(const viz::BeginFrameArgs& args) override {
+    bool should_wait = false;
+    if (config_.should_drop_main_every > 0) {
+      should_wait =
+          args.frame_id.sequence_number % config_.should_drop_main_every == 0;
+    }
+
+    if (should_wait) {
+      base::WaitableEvent wait{base::WaitableEvent::ResetPolicy::MANUAL,
+                               base::WaitableEvent::InitialState::NOT_SIGNALED};
+      {
+        base::AutoLock lock(wait_lock_);
+        wait_ = &wait;
+      }
+      wait.Wait();
+      {
+        base::AutoLock lock(wait_lock_);
+        wait_ = nullptr;
+      }
+    } else if (!TestEnded()) {
+      // Make sure BeginMainFrame keeps being issued.
+      layer_tree_host()->SetNeedsAnimate();
+      if (config_.should_register_main_thread_animation) {
+        animation_host()->SetAnimationCounts(1, true, true);
+      }
+    }
+  }
+
+ protected:
+  // The test configuration options. This is set before the test starts, and
+  // remains unchanged after that. So it is safe to read these fields from
+  // either threads.
+  struct TestConfig {
+    uint32_t should_drop_main_every = 0;
+    uint32_t animation_frames = 0;
+    bool should_register_main_thread_animation = false;
+  } config_;
+
+  // The test expectations. This is set before the test starts, and
+  // remains unchanged after that. So it is safe to read these fields from
+  // either threads.
+  struct TestExpectation {
+    uint32_t min_dropped_main = 0;
+    uint32_t min_dropped_compositor = 0;
+    uint32_t min_dropped_smoothness = 0;
+  } expect_;
+
+ private:
+  // This field is used only on the compositor thread to track how many frames
+  // have been processed.
+  uint32_t presented_frames_ = 0;
+
+  // The |wait_| event is used when the test wants to deliberately force the
+  // main-thread to block while processing begin-main-frames.
+  base::Lock wait_lock_;
+  base::WaitableEvent* wait_ = nullptr;
+
+  // These fields are populated in the compositor thread when the desired number
+  // of frames have been processed. These fields are subsequently compared
+  // against the expectation after the test ends.
+  uint32_t total_frames_ = 0;
+  uint32_t dropped_main_ = 0;
+  uint32_t dropped_compositor_ = 0;
+  uint32_t dropped_smoothness_ = 0;
+};
+
+class DroppedFrameCounterNoDropTest : public DroppedFrameCounterTestBase {
+ public:
+  ~DroppedFrameCounterNoDropTest() override = default;
+
+  void SetUpTestConfigAndExpectations() override {
+    config_.animation_frames = 28;
+    config_.should_register_main_thread_animation = false;
+
+    expect_.min_dropped_main = 0;
+    expect_.min_dropped_compositor = 0;
+    expect_.min_dropped_smoothness = 0;
+  }
+};
+
+MULTI_THREAD_TEST_F(DroppedFrameCounterNoDropTest);
+
+class DroppedFrameCounterMainDropsNoSmoothness
+    : public DroppedFrameCounterTestBase {
+ public:
+  ~DroppedFrameCounterMainDropsNoSmoothness() override = default;
+
+  void SetUpTestConfigAndExpectations() override {
+    config_.animation_frames = 28;
+    config_.should_drop_main_every = 5;
+    config_.should_register_main_thread_animation = false;
+
+    expect_.min_dropped_main = 5;
+    expect_.min_dropped_smoothness = 0;
+  }
+};
+
+MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsNoSmoothness);
+
+class DroppedFrameCounterMainDropsSmoothnessTest
+    : public DroppedFrameCounterTestBase {
+ public:
+  ~DroppedFrameCounterMainDropsSmoothnessTest() override = default;
+
+  void SetUpTestConfigAndExpectations() override {
+    config_.animation_frames = 28;
+    config_.should_drop_main_every = 5;
+    config_.should_register_main_thread_animation = true;
+
+    expect_.min_dropped_main = 5;
+    expect_.min_dropped_smoothness = 5;
+  }
+};
+
+MULTI_THREAD_TEST_F(DroppedFrameCounterMainDropsSmoothnessTest);
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/metrics/frame_sequence_tracker_collection.cc b/cc/metrics/frame_sequence_tracker_collection.cc
index 7c97a48..5e87af55 100644
--- a/cc/metrics/frame_sequence_tracker_collection.cc
+++ b/cc/metrics/frame_sequence_tracker_collection.cc
@@ -66,6 +66,25 @@
     DCHECK_NE(scrolling_thread, ThreadType::kUnknown);
     metrics->SetScrollingThread(scrolling_thread);
   }
+
+  if (type != FrameSequenceTrackerType::kUniversal) {
+    if (metrics->GetEffectiveThread() == ThreadType::kCompositor) {
+      if (compositor_frame_reporting_controller_ &&
+          compositor_thread_driving_smoothness_ == 0) {
+        compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
+            ThreadType::kCompositor, true);
+      }
+      ++compositor_thread_driving_smoothness_;
+    } else {
+      DCHECK_EQ(metrics->GetEffectiveThread(), ThreadType::kMain);
+      if (compositor_frame_reporting_controller_ &&
+          main_thread_driving_smoothness_ == 0) {
+        compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
+            ThreadType::kMain, true);
+      }
+      ++main_thread_driving_smoothness_;
+    }
+  }
   return frame_trackers_[key].get();
 }
 
@@ -108,12 +127,31 @@
   if (!frame_trackers_.contains(key))
     return;
 
-  std::unique_ptr<FrameSequenceTracker> tracker =
-      std::move(frame_trackers_[key]);
-
-  if (compositor_frame_reporting_controller_)
+  auto tracker = std::move(frame_trackers_[key]);
+  if (compositor_frame_reporting_controller_) {
     compositor_frame_reporting_controller_->RemoveActiveTracker(
         tracker->type());
+  }
+
+  if (type != FrameSequenceTrackerType::kUniversal) {
+    if (tracker->metrics()->GetEffectiveThread() == ThreadType::kCompositor) {
+      DCHECK_GT(compositor_thread_driving_smoothness_, 0u);
+      --compositor_thread_driving_smoothness_;
+      if (compositor_frame_reporting_controller_ &&
+          compositor_thread_driving_smoothness_ == 0) {
+        compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
+            ThreadType::kCompositor, false);
+      }
+    } else {
+      DCHECK_GT(main_thread_driving_smoothness_, 0u);
+      --main_thread_driving_smoothness_;
+      if (compositor_frame_reporting_controller_ &&
+          main_thread_driving_smoothness_ == 0) {
+        compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
+            ThreadType::kMain, false);
+      }
+    }
+  }
 
   frame_trackers_.erase(key);
   tracker->ScheduleTerminate();
diff --git a/cc/metrics/frame_sequence_tracker_collection.h b/cc/metrics/frame_sequence_tracker_collection.h
index 0fecfce..98d4566 100644
--- a/cc/metrics/frame_sequence_tracker_collection.h
+++ b/cc/metrics/frame_sequence_tracker_collection.h
@@ -173,6 +173,10 @@
       std::pair<FrameSequenceTrackerType, FrameSequenceMetrics::ThreadType>,
       std::unique_ptr<FrameSequenceMetrics>>
       accumulated_metrics_;
+
+  // Tracks how many smoothness effects are driven by each thread.
+  size_t main_thread_driving_smoothness_ = 0;
+  size_t compositor_thread_driving_smoothness_ = 0;
 };
 
 }  // namespace cc
diff --git a/cc/paint/paint_filter_unittest.cc b/cc/paint/paint_filter_unittest.cc
index 1cf6765..592b9f6 100644
--- a/cc/paint/paint_filter_unittest.cc
+++ b/cc/paint/paint_filter_unittest.cc
@@ -20,9 +20,10 @@
   ScopedResult GetRasterContent(const DrawImage& draw_image) override {
     DCHECK(!draw_image.paint_image().IsPaintWorklet());
     image_count_++;
-    return ScopedResult(DecodedDrawImage(
-        CreateBitmapImage(gfx::Size(10, 10)).GetSkImage(), SkSize::MakeEmpty(),
-        SkSize::Make(1.0f, 1.0f), draw_image.filter_quality(), true));
+    return ScopedResult(
+        DecodedDrawImage(CreateBitmapImage(gfx::Size(10, 10)).GetSwSkImage(),
+                         SkSize::MakeEmpty(), SkSize::Make(1.0f, 1.0f),
+                         draw_image.filter_quality(), true));
   }
   int image_count_ = 0;
 };
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index c14acf6..140365b 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -66,6 +66,10 @@
     return false;
   if (is_multipart_ != other.is_multipart_)
     return false;
+  if (texture_backing_ != other.texture_backing_)
+    return false;
+  if (paint_worklet_input_ != other.paint_worklet_input_)
+    return false;
   return true;
 }
 
@@ -378,7 +382,7 @@
 }
 
 size_t PaintImage::FrameCount() const {
-  if (!GetSkImage())
+  if (!*this)
     return 0u;
   return paint_image_generator_
              ? paint_image_generator_->GetFrameMetadata().size()
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index fff7d31f..0e9c31e 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -265,7 +265,7 @@
     return paint_worklet_input_ ? 0 : GetSkImage()->uniqueID();
   }
   explicit operator bool() const {
-    return paint_worklet_input_ || !!GetSkImage() || texture_backing_;
+    return paint_worklet_input_ || cached_sk_image_ || texture_backing_;
   }
   bool IsLazyGenerated() const {
     return paint_record_ || paint_image_generator_;
@@ -336,6 +336,7 @@
   friend class PlaybackImageProvider;
   friend class DrawImageRectOp;
   friend class DrawImageOp;
+  friend class AcceleratedStaticBitmapImageTest;
 
   bool DecodeFromGenerator(void* memory,
                            SkImageInfo* info,
diff --git a/cc/paint/paint_image_unittest.cc b/cc/paint/paint_image_unittest.cc
index ac82cbd7..dfda9aa18 100644
--- a/cc/paint/paint_image_unittest.cc
+++ b/cc/paint/paint_image_unittest.cc
@@ -67,7 +67,7 @@
 
 TEST(PaintImageTest, GetSkImageForFrameNotGeneratorBacked) {
   PaintImage image = CreateBitmapImage(gfx::Size(10, 10));
-  EXPECT_EQ(image.GetSkImage(),
+  EXPECT_EQ(image.GetSwSkImage(),
             image.GetSkImageForFrame(PaintImage::kDefaultFrameIndex,
                                      PaintImage::GetNextGeneratorClientId()));
 }
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 975fe89f..d00b3140 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -2637,9 +2637,8 @@
   for (auto* base_op : PaintOpBuffer::Iterator(&buffer)) {
     auto* op = static_cast<DrawImageOp*>(base_op);
 
-    SkRect image_rect =
-        SkRect::MakeXYWH(op->left, op->top, op->image.GetSkImage()->width(),
-                         op->image.GetSkImage()->height());
+    SkRect image_rect = SkRect::MakeXYWH(op->left, op->top, op->image.width(),
+                                         op->image.height());
     ASSERT_TRUE(PaintOp::GetBounds(op, &rect));
     EXPECT_EQ(rect, image_rect.makeSorted());
   }
diff --git a/cc/raster/playback_image_provider.cc b/cc/raster/playback_image_provider.cc
index f3fae3b6..224a1f2 100644
--- a/cc/raster/playback_image_provider.cc
+++ b/cc/raster/playback_image_provider.cc
@@ -46,7 +46,7 @@
 
   const PaintImage& paint_image = draw_image.paint_image();
   if (settings_->images_to_skip.count(paint_image.stable_id()) != 0) {
-    DCHECK(paint_image.GetSkImage()->isLazyGenerated());
+    DCHECK(paint_image.IsLazyGenerated());
     return ScopedResult();
   }
 
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 5670687f..14a04f5 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1327,6 +1327,8 @@
     public_deps += [
       "//chrome/browser/resources:bluetooth_pairing_dialog_resources",
       "//chrome/browser/resources:multidevice_internals_resources",
+      "//chrome/browser/resources:nearby_shared_resources",
+      "//chrome/browser/resources:nearby_shared_resources_v3",
       "//chrome/browser/resources:os_settings_resources",
       "//chrome/browser/resources/chromeos:cellular_setup_resources",
       "//chrome/browser/resources/chromeos:multidevice_setup_resources",
diff --git a/chrome/VERSION b/chrome/VERSION
index 7b9c74a6..a6e9e1a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=87
 MINOR=0
-BUILD=4246
+BUILD=4247
 PATCH=0
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java
index 14dcb4e..36b4cee3 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantPreferencesUtil.java
@@ -55,14 +55,17 @@
     /** Increments the number of times a user has explicitly canceled a lite script. */
     static void incrementAutofillAssistantNumberOfLiteScriptsCanceled() {
         int numCanceled = getAutofillAssistantNumberOfLiteScriptsCanceled() + 1;
-        SharedPreferencesManager.getInstance().writeInt(
+        SharedPreferencesManager sharedPreferencesManager = SharedPreferencesManager.getInstance();
+        sharedPreferencesManager.writeInt(
                 ChromePreferenceKeys.AUTOFILL_ASSISTANT_NUMBER_OF_LITE_SCRIPTS_CANCELED,
                 numCanceled);
-        if (isAutofillAssistantLiteScriptCancelThresholdReached()) {
+        if (isAutofillAssistantLiteScriptCancelThresholdReached()
+                && !sharedPreferencesManager.contains(
+                        ChromePreferenceKeys.AUTOFILL_ASSISTANT_ENABLED)) {
             // Disable the flag, such that users will not see the lite script again. This will also
             // create the setting in the Chrome settings, if it was not present before, which will
             // allow users to opt back in.
-            SharedPreferencesManager.getInstance().writeBoolean(
+            sharedPreferencesManager.writeBoolean(
                     ChromePreferenceKeys.AUTOFILL_ASSISTANT_ENABLED, false);
         }
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
index 13f335b..9d3d271 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/password_manager/settings/PasswordSettingsTest.java
@@ -895,6 +895,7 @@
     @SmallTest
     @Feature({"Preferences"})
     @EnableFeatures(ChromeFeatureList.PASSWORD_EDITING_ANDROID)
+    @DisabledTest(message = "crbug.com/1122310")
     public void testPasswordEditingMethodWasCalled() throws Exception {
         PasswordEditingDelegateProvider.getInstance().setPasswordEditingDelegate(
                 mMockPasswordEditingDelegate);
diff --git a/chrome/app/nearby_share_strings.grdp b/chrome/app/nearby_share_strings.grdp
index e4e3d5f..79bf284 100644
--- a/chrome/app/nearby_share_strings.grdp
+++ b/chrome/app/nearby_share_strings.grdp
@@ -36,6 +36,32 @@
     {COUNT, plural, =1 {1 item} other {# items}}
   </message>
 
+  <!-- Settings Strings -->
+  <message name="IDS_NEARBY_VISIBLITY_ALL_CONTACTS" desc="Describes the user preference state for the user to be visibile to all their contacts in the Nearby Share feature.">
+    All contacts
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_ALL_CONTACTS_DESCRIPTION" desc="Accessibility description that explains to the user that their current visibility setting is all contacts for the Nearby Share feature." is_accessibility_with_no_ui="true">
+    Current visibility setting is all contacts
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_SOME_CONTACTS" desc="Describes the user preference state for the user to be visibile to some selected set of their contacts in the Nearby Share feature.">
+    Some contacts
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_SOME_CONTACTS_DESCRIPTION" desc="Accessibility description that explains to the user that their current visibility setting is some contacts for the Nearby Share feature." is_accessibility_with_no_ui="true">
+    Current visibility setting is some contacts
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_HIDDEN" desc="Describes the user preference state for the user to be visibile to none of their contacts (hidden) in the Nearby Share feature.">
+    Hidden
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_HIDDEN_DESCRIPTION" desc="Accessibility description that explains to the user that their current visibility setting hidden for the Nearby Share feature." is_accessibility_with_no_ui="true">
+    Current visibility setting is hidden
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_UNKNOWN" desc="Describes the user preference state when the user has not chosen a visibility preference yet in the Nearby Share feature.">
+    Choose your visibility
+  </message>
+  <message name="IDS_NEARBY_VISIBLITY_UNKNOWN_DESCRIPTION" desc="Accessibility description that explains to the user that their current visibility setting is not set yet for the Nearby Share feature." is_accessibility_with_no_ui="true">
+    Current visibility setting is not set yet
+  </message>
+
   <!-- Notification strings -->
   <message name="IDS_NEARBY_NOTIFICATION_CONNECTION_REQUEST_MESSAGE" desc="Text shown as the message of a notfication when a nearby device requests a connection via Nearby Share.">
     {COUNT, plural,
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_ALL_CONTACTS.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_ALL_CONTACTS.png.sha1
new file mode 100644
index 0000000..530d1e92
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_ALL_CONTACTS.png.sha1
@@ -0,0 +1 @@
+bde8e0133be62a897b767b49f6ddad8657901259
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_HIDDEN.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_HIDDEN.png.sha1
new file mode 100644
index 0000000..4df6d08
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_HIDDEN.png.sha1
@@ -0,0 +1 @@
+e9f245e87904252d534adb750109343349f8d17b
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_SOME_CONTACTS.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_SOME_CONTACTS.png.sha1
new file mode 100644
index 0000000..7d0ecb5f
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_SOME_CONTACTS.png.sha1
@@ -0,0 +1 @@
+3eb103f202cfe87660f315bacd8dbbcd4c898715
\ No newline at end of file
diff --git a/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_UNKNOWN.png.sha1 b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_UNKNOWN.png.sha1
new file mode 100644
index 0000000..021dccb2
--- /dev/null
+++ b/chrome/app/nearby_share_strings_grdp/IDS_NEARBY_VISIBLITY_UNKNOWN.png.sha1
@@ -0,0 +1 @@
+6c459c3b3fb6afa6d23f19e4f44f245be1a54da5
\ No newline at end of file
diff --git a/chrome/app/shared_settings_strings.grdp b/chrome/app/shared_settings_strings.grdp
index b1d7acf..686a80b 100644
--- a/chrome/app/shared_settings_strings.grdp
+++ b/chrome/app/shared_settings_strings.grdp
@@ -147,6 +147,15 @@
   <message name="IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_OFFLINE_DESCRIPTION" desc="Description for scren readers, not displayed in UI, specifying the current data usage setting where transfers will only take place offline for the Nearby Share feature." is_accessibility_with_no_ui="true">
     Current data usage setting is Without internet
   </message>
+  <message name="IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE" desc="Text for the row in settings which allows a user to set their preference for the visibility of their device with their contacts for the Nearby Share feature.">
+    Device visibility
+  </message>
+  <message name="IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY" desc="Label for the button that opens the dialog which allows a user to set their preference for the visibility of their device with their contacts for the Nearby Share feature.">
+    View device visibility
+  </message>
+  <message name="IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE" desc="Title for the dialog which allows a user to set their preference for the visibility of their device with their contacts for the Nearby Share feature.">
+    Device visibility
+  </message>
 
  <!-- Personalization Options SubPage (strings used by the <settings-personalization-options> element) -->
   <message name="IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION" desc="The label of the checkbox to enable/disable url keyed anonymized data collection.">
diff --git a/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE.png.sha1 b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE.png.sha1
new file mode 100644
index 0000000..fe1a140
--- /dev/null
+++ b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE.png.sha1
@@ -0,0 +1 @@
+afa676ee3ca1b1563bfd5dd3f0a428669b21c44f
\ No newline at end of file
diff --git a/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY.png.sha1 b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY.png.sha1
new file mode 100644
index 0000000..9e83b8e
--- /dev/null
+++ b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY.png.sha1
@@ -0,0 +1 @@
+1ab039c9f2960ce64f40f57e7c096124d91e1b07
\ No newline at end of file
diff --git a/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE.png.sha1 b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE.png.sha1
new file mode 100644
index 0000000..338a27e
--- /dev/null
+++ b/chrome/app/shared_settings_strings_grdp/IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE.png.sha1
@@ -0,0 +1 @@
+33401ff9d166e6d792ec4d2b53ce0133a7ced4a9
\ No newline at end of file
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 183c5fe..4f7fe3a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3116,12 +3116,6 @@
          kAutofillKeyboardAccessoryFeatureVariations,
          "AutofillKeyboardAccessory")},
 #endif  // OS_ANDROID
-#if defined(OS_WIN)
-    {"try-supported-channel-layouts",
-     flag_descriptions::kTrySupportedChannelLayoutsName,
-     flag_descriptions::kTrySupportedChannelLayoutsDescription, kOsWin,
-     SINGLE_VALUE_TYPE(switches::kTrySupportedChannelLayouts)},
-#endif  // OS_WIN
 #if defined(OS_MAC)
     {"mac-syscall-sandbox", flag_descriptions::kMacSyscallSandboxName,
      flag_descriptions::kMacSyscallSandboxDescription, kOsMac,
@@ -5228,6 +5222,11 @@
      flag_descriptions::kHideArcMediaNotificationsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kHideArcMediaNotifications)},
 
+    {"media-notifications-counter",
+     flag_descriptions::kMediaNotificationsCounterName,
+     flag_descriptions::kMediaNotificationsCounterDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kMediaNotificationsCounter)},
+
     {"reduce-display-notifications",
      flag_descriptions::kReduceDisplayNotificationsName,
      flag_descriptions::kReduceDisplayNotificationsDescription, kOsCrOS,
diff --git a/chrome/browser/apps/app_service/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon_factory.cc
index bfe59640..fbd423e2b 100644
--- a/chrome/browser/apps/app_service/app_icon_factory.cc
+++ b/chrome/browser/apps/app_service/app_icon_factory.cc
@@ -543,7 +543,7 @@
   icon_scale_for_compressed_response_ = icon_scale_;
 
   base::Optional<IconPurpose> icon_purpose_to_read =
-      GetIconPurpose(web_app_id, icon_manager, icon_size_in_px_);
+      GetIconPurpose(web_app_id, icon_manager, size_hint_in_dip_);
 
   if (!icon_purpose_to_read.has_value()) {
     MaybeLoadFallbackOrCompleteEmpty();
diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc
index 19d93b5..70d67f8c 100644
--- a/chrome/browser/chrome_browser_interface_binders.cc
+++ b/chrome/browser/chrome_browser_interface_binders.cc
@@ -523,13 +523,7 @@
   RegisterWebUIControllerInterfaceBinder<downloads::mojom::PageHandlerFactory,
                                          DownloadsUI>(map);
 
-  if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
     RegisterWebUIControllerInterfaceBinder<
-        nearby_share::mojom::DiscoveryManager,
-        nearby_share::NearbyShareDialogUI>(map);
-  }
-
-  RegisterWebUIControllerInterfaceBinder<
       new_tab_page::mojom::PageHandlerFactory, NewTabPageUI>(map);
 
   RegisterWebUIControllerInterfaceBinder<
@@ -672,16 +666,11 @@
         nearby_share::mojom::NearbyShareSettings,
         chromeos::settings::OSSettingsUI, nearby_share::NearbyShareDialogUI>(
         map);
-  }
-#endif  // defined(OS_CHROMEOS)
-
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
-  if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
     RegisterWebUIControllerInterfaceBinder<
-        nearby_share::mojom::NearbyShareSettings,
+        nearby_share::mojom::DiscoveryManager,
         nearby_share::NearbyShareDialogUI>(map);
   }
-#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_CHROMEOS)
 }
 
 }  // namespace internal
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 93d7c290..d85f351b 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -526,8 +526,7 @@
         TestCase("directoryTreeRecentsSubtypeScroll").EnableUnifiedMediaView(),
         TestCase("directoryTreeHorizontalScroll"),
         TestCase("directoryTreeExpandHorizontalScroll"),
-        // Disabled. Fails on internal ChromeOS bot. https://crbug.com/1061821.
-        // TestCase("directoryTreeExpandHorizontalScrollRTL"),
+        TestCase("directoryTreeExpandHorizontalScrollRTL"),
         TestCase("directoryTreeVerticalScroll"),
         TestCase("directoryTreeExpandFolder")));
 
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 49700b2b..afff15f 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -369,15 +369,6 @@
   results->SetBoolean("hotrodmode", g_hotrod_keyboard_enabled);
   std::unique_ptr<base::ListValue> features(new base::ListValue());
 
-  // TODO(https://crbug.com/880659): Cleanup these flags after removing these
-  // flags from IME extension.
-  features->AppendString(GenerateFeatureFlag("floatingkeyboard", true));
-  features->AppendString(GenerateFeatureFlag("gesturetyping", true));
-  // TODO(https://crbug.com/890134): Implement gesture editing.
-  features->AppendString(GenerateFeatureFlag("gestureediting", false));
-  features->AppendString(GenerateFeatureFlag("fullscreenhandwriting", false));
-  features->AppendString(GenerateFeatureFlag("virtualkeyboardmdui", true));
-
   keyboard::KeyboardConfig config = keyboard_client->GetKeyboardConfig();
   // TODO(oka): Change this to use config.voice_input.
   features->AppendString(GenerateFeatureFlag(
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e8e52106..11690fb 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2975,6 +2975,11 @@
     "expiry_milestone": 88
   },
   {
+    "name": "media-notifications-counter",
+    "owners": [ "gzadina@google.com", "joelhockey", "tengs" ],
+    "expiry_milestone": 90
+  },
+  {
     "name": "media-router-cast-allow-all-ips",
     "owners": [ "mfoltz" ],
     // This flag is used by users with unusual network configurations to allow
@@ -4360,11 +4365,6 @@
     "expiry_milestone": 86
   },
   {
-    "name": "try-supported-channel-layouts",
-    "owners": [ "dalecurtis" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "turn-off-streaming-media-caching-always",
     "owners": [ "shawnpi@microsoft.com", "cassew@google.com" ],
     "expiry_milestone": 87
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 8238816..87dce039 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2376,15 +2376,6 @@
     "Enables the prototype Trust Token API "
     "(https://github.com/wicg/trust-token-api).";
 
-const char kTrySupportedChannelLayoutsName[] =
-    "Causes audio output streams to check if channel layouts other than the "
-    "default hardware layout are available.";
-const char kTrySupportedChannelLayoutsDescription[] =
-    "Causes audio output streams to check if channel layouts other than the "
-    "default hardware layout are available. Turning this on will allow the OS "
-    "to do stereo to surround expansion if supported. May expose third party "
-    "driver bugs, use with caution.";
-
 const char kTurnOffStreamingMediaCachingOnBatteryName[] =
     "Turn off caching of streaming media to disk while on battery power.";
 const char kTurnOffStreamingMediaCachingOnBatteryDescription[] =
@@ -4190,6 +4181,11 @@
 const char kMediaAppDescription[] =
     "Enables the chrome://media-app System Web App (SWA)";
 
+const char kMediaNotificationsCounterName[] = "Media Notifications Counter";
+const char kMediaNotificationsCounterDescription[] =
+    "Remove media notifications from the notification counter in the status "
+    "area";
+
 const char kMediaSessionNotificationsName[] = "Media session notifications";
 const char kMediaSessionNotificationsDescription[] =
     "Shows notifications for media sessions showing the currently playing "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 2e1b937..e464d1f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1373,9 +1373,6 @@
 extern const char kTrustTokensName[];
 extern const char kTrustTokensDescription[];
 
-extern const char kTrySupportedChannelLayoutsName[];
-extern const char kTrySupportedChannelLayoutsDescription[];
-
 extern const char kTurnOffStreamingMediaCachingOnBatteryName[];
 extern const char kTurnOffStreamingMediaCachingOnBatteryDescription[];
 
@@ -2442,6 +2439,9 @@
 extern const char kMediaAppName[];
 extern const char kMediaAppDescription[];
 
+extern const char kMediaNotificationsCounterName[];
+extern const char kMediaNotificationsCounterDescription[];
+
 extern const char kMediaSessionNotificationsName[];
 extern const char kMediaSessionNotificationsDescription[];
 
diff --git a/chrome/browser/lite_video/lite_video_decider.cc b/chrome/browser/lite_video/lite_video_decider.cc
index ecbf3997..31e1bab 100644
--- a/chrome/browser/lite_video/lite_video_decider.cc
+++ b/chrome/browser/lite_video/lite_video_decider.cc
@@ -16,6 +16,8 @@
 #include "chrome/browser/lite_video/lite_video_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/blocklist/opt_out_blocklist/opt_out_store.h"
+#include "components/optimization_guide/optimization_guide_decider.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/web_contents.h"
@@ -71,18 +73,25 @@
   return effective_connection_type >= lite_video::features::MinLiteVideoECT();
 }
 
-
 }  // namespace
 
 namespace lite_video {
 
 LiteVideoDecider::LiteVideoDecider(
     std::unique_ptr<blocklist::OptOutStore> opt_out_store,
-    base::Clock* clock)
-    : hint_cache_(std::make_unique<LiteVideoHintCache>()) {
+    base::Clock* clock,
+    optimization_guide::OptimizationGuideDecider* opt_guide_decider)
+    : hint_cache_(std::make_unique<LiteVideoHintCache>()),
+      opt_guide_decider_(opt_guide_decider),
+      cached_opt_guide_hints_(features::MaxOptimizationGuideHintCacheSize()) {
   user_blocklist_ = std::make_unique<LiteVideoUserBlocklist>(
       std::move(opt_out_store), clock, this);
 
+  if (opt_guide_decider_) {
+    opt_guide_decider_->RegisterOptimizationTypes(
+        {optimization_guide::proto::LITE_VIDEO});
+  }
+
   network::NetworkQualityTracker* nqe_tracker =
       g_browser_process->network_quality_tracker();
   if (nqe_tracker) {
@@ -118,7 +127,9 @@
       LiteVideoBlocklistReason::kUnknown;
   if (!IsLiteVideoAllowedForUser(Profile::FromBrowserContext(
           navigation_handle->GetWebContents()->GetBrowserContext()))) {
-    std::move(callback).Run(base::nullopt, blocklist_reason);
+    std::move(callback).Run(
+        base::nullopt, blocklist_reason,
+        optimization_guide::OptimizationGuideDecision::kFalse);
     return;
   }
 
@@ -129,20 +140,24 @@
                       features::LiteVideoTargetDownlinkRTTLatency(),
                       features::LiteVideoKilobytesToBufferBeforeThrottle(),
                       features::LiteVideoMaxThrottlingDelay()),
-        blocklist_reason);
+        blocklist_reason, optimization_guide::OptimizationGuideDecision::kTrue);
     return;
   }
 
   if (!CanApplyOnCurrentNetworkConditions(is_cellular_network_,
                                           current_effective_connection_type_)) {
-    std::move(callback).Run(base::nullopt, blocklist_reason);
+    std::move(callback).Run(
+        base::nullopt, blocklist_reason,
+        optimization_guide::OptimizationGuideDecision::kFalse);
     return;
   }
 
   GURL url = navigation_handle->GetURL();
 
   if (!url.SchemeIsHTTPOrHTTPS()) {
-    std::move(callback).Run(base::nullopt, blocklist_reason);
+    std::move(callback).Run(
+        base::nullopt, blocklist_reason,
+        optimization_guide::OptimizationGuideDecision::kFalse);
     return;
   }
 
@@ -159,27 +174,88 @@
                            : LiteVideoBlocklistReason::kNavigationForwardBack;
     ScopedLiteVideoDecisionRecorder scoped_decision_recorder(
         blocklist_reason, navigation_handle->IsInMainFrame());
-    std::move(callback).Run(base::nullopt, blocklist_reason);
+    std::move(callback).Run(
+        base::nullopt, blocklist_reason,
+        optimization_guide::OptimizationGuideDecision::kFalse);
     return;
   }
 
   blocklist_reason =
       user_blocklist_->IsLiteVideoAllowedOnNavigation(navigation_handle);
-  ScopedLiteVideoDecisionRecorder scoped_decision_recorder(
-      blocklist_reason, navigation_handle->IsInMainFrame());
+
+  if (opt_guide_decider_) {
+    // This relies on the optimization guide for hints.
+    if (navigation_handle->IsInMainFrame()) {
+      opt_guide_decider_->CanApplyOptimizationAsync(
+          navigation_handle, optimization_guide::proto::LITE_VIDEO,
+          base::BindOnce(&LiteVideoDecider::OnOptimizationGuideHintAvailable,
+                         weak_ptr_factory_.GetWeakPtr(),
+                         navigation_handle->GetURL(), blocklist_reason,
+                         std::move(callback)));
+
+      UpdateBlocklists(navigation_handle, blocklist_reason);
+      return;
+    }
+
+    // For subframes, check if a hint is cached that can be used
+    // immediately. Otherwise, the callback from the optimization guide
+    // will trigger subframes to get the supplied hint.
+    base::Optional<LiteVideoHint> hint;
+    optimization_guide::OptimizationGuideDecision opt_guide_decision =
+        optimization_guide::OptimizationGuideDecision::kUnknown;
+    GURL mainframe_url =
+        navigation_handle->GetWebContents()->GetLastCommittedURL();
+    auto it = cached_opt_guide_hints_.Get(mainframe_url.host());
+    if (it != cached_opt_guide_hints_.end()) {
+      hint = it->second;
+      // An entry with an empty hint means that the optimization guide
+      // decision was kFalse.
+      opt_guide_decision =
+          hint ? optimization_guide::OptimizationGuideDecision::kTrue
+               : optimization_guide::OptimizationGuideDecision::kFalse;
+    }
+
+    UpdateBlocklists(navigation_handle, blocklist_reason);
+
+    ScopedLiteVideoDecisionRecorder scoped_decision_recorder(
+        blocklist_reason, navigation_handle->IsInMainFrame());
+    if (hint)
+      scoped_decision_recorder.set_has_hint_for_host(true);
+
+    std::move(callback).Run(hint, blocklist_reason, opt_guide_decision);
+    return;
+  }
 
   base::Optional<LiteVideoHint> hint =
       hint_cache_->GetHintForNavigationURL(url);
+  ScopedLiteVideoDecisionRecorder scoped_decision_recorder(
+      blocklist_reason, navigation_handle->IsInMainFrame());
+
   if (hint)
     scoped_decision_recorder.set_has_hint_for_host(true);
 
   if (blocklist_reason != LiteVideoBlocklistReason::kAllowed || !hint) {
-    std::move(callback).Run(base::nullopt, blocklist_reason);
+    std::move(callback).Run(
+        base::nullopt, blocklist_reason,
+        optimization_guide::OptimizationGuideDecision::kFalse);
     return;
   }
 
-  // The navigation will have the LiteVideo optimization triggered so
-  // update the blocklist.
+  UpdateBlocklists(navigation_handle, blocklist_reason);
+  std::move(callback).Run(hint, blocklist_reason,
+                          optimization_guide::OptimizationGuideDecision::kTrue);
+}
+
+void LiteVideoDecider::UpdateBlocklists(
+    content::NavigationHandle* navigation_handle,
+    LiteVideoBlocklistReason blocklist_reason) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(navigation_handle);
+  if (blocklist_reason != LiteVideoBlocklistReason::kAllowed)
+    return;
+
+  // The navigation was not blocklisted and may
+  // have the LiteVideo optimization triggered so update the blocklist.
   user_blocklist_->AddNavigationToBlocklist(navigation_handle, false);
 
   navigation_handle->IsInMainFrame()
@@ -187,7 +263,55 @@
       : DidMediaRebuffer(
             navigation_handle->GetWebContents()->GetLastCommittedURL(),
             navigation_handle->GetURL(), false);
-  std::move(callback).Run(hint, blocklist_reason);
+}
+
+void LiteVideoDecider::OnOptimizationGuideHintAvailable(
+    const GURL& mainframe_url,
+    LiteVideoBlocklistReason blocklist_reason,
+    LiteVideoHintCallback callback,
+    optimization_guide::OptimizationGuideDecision decision,
+    const optimization_guide::OptimizationMetadata& metadata) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(opt_guide_decider_);
+
+  // This is only called on a mainframe navigation.
+  ScopedLiteVideoDecisionRecorder scoped_decision_recorder(
+      blocklist_reason, /*is_mainframe=*/true);
+
+  if (decision == optimization_guide::OptimizationGuideDecision::kTrue)
+    scoped_decision_recorder.set_has_hint_for_host(true);
+
+  // If the decision is false, then add an empty entry into the hint cache
+  // so that subframes with this mainframe host will return false.
+  if (decision == optimization_guide::OptimizationGuideDecision::kFalse) {
+    cached_opt_guide_hints_.Put(mainframe_url.host(), base::nullopt);
+    UMA_HISTOGRAM_COUNTS_100("LiteVideo.LiteVideoDecider.OptGuideHintCacheSize",
+                             cached_opt_guide_hints_.size());
+  }
+
+  if (blocklist_reason != LiteVideoBlocklistReason::kAllowed ||
+      decision != optimization_guide::OptimizationGuideDecision::kTrue) {
+    std::move(callback).Run(base::nullopt, blocklist_reason, decision);
+    return;
+  }
+
+  LiteVideoHint hint =
+      LiteVideoHint(switches::GetDefaultDownlinkBandwidthKbps(),
+                    features::LiteVideoTargetDownlinkRTTLatency(),
+                    features::LiteVideoKilobytesToBufferBeforeThrottle(),
+                    features::LiteVideoMaxThrottlingDelay());
+
+  base::Optional<optimization_guide::proto::LiteVideoMetadata>
+      lite_video_metadata =
+          metadata
+              .ParsedMetadata<optimization_guide::proto::LiteVideoMetadata>();
+  if (lite_video_metadata && lite_video_metadata->has_lite_video_hint())
+    hint = LiteVideoHint(lite_video_metadata->lite_video_hint());
+
+  cached_opt_guide_hints_.Put(mainframe_url.host(), hint);
+  UMA_HISTOGRAM_COUNTS_100("LiteVideo.LiteVideoDecider.OptGuideHintCacheSize",
+                           cached_opt_guide_hints_.size());
+  std::move(callback).Run(hint, blocklist_reason, decision);
 }
 
 void LiteVideoDecider::OnUserBlocklistedStatusChange(bool blocklisted) {
@@ -214,12 +338,12 @@
       network::NetworkConnectionTracker::IsConnectionCellular(type);
 }
 
-void LiteVideoDecider::ClearBlocklist(const base::Time& delete_begin,
-                                      const base::Time& delete_end) {
+void LiteVideoDecider::ClearData(const base::Time& delete_begin,
+                                 const base::Time& delete_end) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (user_blocklist_) {
+  if (user_blocklist_)
     user_blocklist_->ClearBlockList(delete_begin, delete_end);
-  }
+  cached_opt_guide_hints_.Clear();
 }
 
 void LiteVideoDecider::OnBlocklistCleared(base::Time time) {
diff --git a/chrome/browser/lite_video/lite_video_decider.h b/chrome/browser/lite_video/lite_video_decider.h
index 14600bf..6212aa54 100644
--- a/chrome/browser/lite_video/lite_video_decider.h
+++ b/chrome/browser/lite_video/lite_video_decider.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include "base/containers/mru_cache.h"
 #include "base/optional.h"
 #include "base/time/clock.h"
 #include "chrome/browser/lite_video/lite_video_hint_cache.h"
@@ -20,11 +21,18 @@
 class OptOutStore;
 }  // namespace blocklist
 
+namespace optimization_guide {
+class OptimizationGuideDecider;
+enum class OptimizationGuideDecision;
+class OptimizationMetadata;
+}  // namespace optimization_guide
+
 namespace lite_video {
 
-using LiteVideoHintCallback =
-    base::OnceCallback<void(base::Optional<LiteVideoHint> hint,
-                            LiteVideoBlocklistReason blocklist_reason)>;
+using LiteVideoHintCallback = base::OnceCallback<void(
+    base::Optional<LiteVideoHint> hint,
+    LiteVideoBlocklistReason blocklist_reason,
+    optimization_guide::OptimizationGuideDecision opt_guide_decision)>;
 
 // The LiteVideoDecider makes the decision on whether LiteVideos should be
 // applied to a navigation and provides the parameters to use when
@@ -34,8 +42,10 @@
       public network::NetworkConnectionTracker::NetworkConnectionObserver,
       public network::NetworkQualityTracker::EffectiveConnectionTypeObserver {
  public:
-  LiteVideoDecider(std::unique_ptr<blocklist::OptOutStore> opt_out_store,
-                   base::Clock* clock);
+  LiteVideoDecider(
+      std::unique_ptr<blocklist::OptOutStore> opt_out_store,
+      base::Clock* clock,
+      optimization_guide::OptimizationGuideDecider* opt_guide_decider);
   ~LiteVideoDecider() override;
 
   // Determine if the navigation can have the LiteVideo optimization applied. It
@@ -68,10 +78,9 @@
   void OnEffectiveConnectionTypeChanged(
       net::EffectiveConnectionType type) override;
 
-  // Purge all the user browsing data within |user_blocklist_| between
-  // the provided time ranges.
-  void ClearBlocklist(const base::Time& delete_begin,
-                      const base::Time& delete_end);
+  // Purge all the user browsing data within |user_blocklist_|  between
+  // the provided time ranges and all data within |cached_opt_guide_hints_|.
+  void ClearData(const base::Time& delete_begin, const base::Time& delete_end);
 
   // Update |user_blocklist_| that a rebuffer event consided an opt-out on the
   // mainframe and subframe URLs occurred.
@@ -79,7 +88,27 @@
                         base::Optional<GURL> subframe_url,
                         bool opt_out);
 
+  // Set the optimization guide decider used by |this| for testing only.
+  void SetOptimizationGuideDeciderForTesting(
+      optimization_guide::OptimizationGuideDecider* opt_guide_decider) {
+    opt_guide_decider_ = opt_guide_decider;
+  }
+
  private:
+  // The result of the query to the optimization guide based on the
+  // |mainframe_url|.
+  void OnOptimizationGuideHintAvailable(
+      const GURL& mainframe_url,
+      LiteVideoBlocklistReason blocklist_reason,
+      LiteVideoHintCallback callback,
+      optimization_guide::OptimizationGuideDecision decision,
+      const optimization_guide::OptimizationMetadata& metadata);
+
+  // Update the blocklists based on the navigation and the provided blocklist
+  // reason.
+  void UpdateBlocklists(content::NavigationHandle* navigation_handle,
+                        LiteVideoBlocklistReason blocklist_reason);
+
   // The hint cache that holds LiteVideoHints that specify the parameters
   // for throttling media requests for that navigation.
   std::unique_ptr<LiteVideoHintCache> hint_cache_;
@@ -99,7 +128,18 @@
   net::EffectiveConnectionType current_effective_connection_type_ =
       net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
 
+  // The optimization guide decider to consult for remote predictions.
+  optimization_guide::OptimizationGuideDecider* opt_guide_decider_ = nullptr;
+
+  // The store of hints provided by the optimization guide keyed by mainframe
+  // host. If the hint is empty, then the optimization guide returned kFalse.
+  base::HashingMRUCache<std::string, base::Optional<LiteVideoHint>>
+      cached_opt_guide_hints_;
+
   SEQUENCE_CHECKER(sequence_checker_);
+
+  // Used to get a weak pointer to |this|.
+  base::WeakPtrFactory<LiteVideoDecider> weak_ptr_factory_{this};
 };
 
 }  // namespace lite_video
diff --git a/chrome/browser/lite_video/lite_video_decider_unittest.cc b/chrome/browser/lite_video/lite_video_decider_unittest.cc
index e75cd8b8..b98b56a3 100644
--- a/chrome/browser/lite_video/lite_video_decider_unittest.cc
+++ b/chrome/browser/lite_video/lite_video_decider_unittest.cc
@@ -23,6 +23,9 @@
 #include "components/blocklist/opt_out_blocklist/opt_out_blocklist.h"
 #include "components/blocklist/opt_out_blocklist/opt_out_blocklist_delegate.h"
 #include "components/blocklist/opt_out_blocklist/opt_out_store.h"
+#include "components/optimization_guide/optimization_guide_decider.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
+#include "components/optimization_guide/test_optimization_guide_decider.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_navigation_handle.h"
 #include "content/public/test/test_renderer_host.h"
@@ -79,13 +82,79 @@
   std::map<GURL, lite_video::LiteVideoHint> hint_cache_;
 };
 
+class TestOptimizationGuideDecider
+    : public optimization_guide::TestOptimizationGuideDecider {
+ public:
+  TestOptimizationGuideDecider() = default;
+  ~TestOptimizationGuideDecider() override = default;
+
+  void RegisterOptimizationTypes(
+      const std::vector<optimization_guide::proto::OptimizationType>&
+          optimization_types) override {
+    registered_optimization_types_ =
+        base::flat_set<optimization_guide::proto::OptimizationType>(
+            optimization_types.begin(), optimization_types.end());
+  }
+
+  // Returns the optimization types registered with the Optimization Guide
+  // Decider.
+  base::flat_set<optimization_guide::proto::OptimizationType>
+  registered_optimization_types() {
+    return registered_optimization_types_;
+  }
+
+  void CanApplyOptimizationAsync(
+      content::NavigationHandle* navigation_handle,
+      optimization_guide::proto::OptimizationType optimization_type,
+      optimization_guide::OptimizationGuideDecisionCallback callback) override {
+    GURL url = navigation_handle->GetURL();
+
+    auto response_iter =
+        responses_.find(std::make_tuple(url, optimization_type));
+    if (response_iter == responses_.end()) {
+      std::move(callback).Run(
+          optimization_guide::OptimizationGuideDecision::kFalse,
+          optimization_guide::OptimizationMetadata());
+      return;
+    }
+
+    auto response = response_iter->second;
+    std::move(callback).Run(std::get<0>(response), std::get<1>(response));
+  }
+
+  void SetResponses(
+      std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
+               std::tuple<optimization_guide::OptimizationGuideDecision,
+                          optimization_guide::OptimizationMetadata>>
+          responses) {
+    responses_ = responses;
+  }
+
+ private:
+  // The optimization types that were registered with the Optimization Guide
+  // Decider.
+  base::flat_set<optimization_guide::proto::OptimizationType>
+      registered_optimization_types_;
+
+  std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
+           std::tuple<optimization_guide::OptimizationGuideDecision,
+                      optimization_guide::OptimizationMetadata>>
+      responses_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestOptimizationGuideDecider);
+};
+
 class LiteVideoDeciderTest : public ChromeRenderViewHostTestHarness {
  public:
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
     scoped_feature_list_.InitAndEnableFeature({::features::kLiteVideo});
-    lite_video_decider_ =
-        std::make_unique<lite_video::LiteVideoDecider>(nullptr, &test_clock_);
+
+    optimization_guide_decider_ =
+        std::make_unique<TestOptimizationGuideDecider>();
+
+    lite_video_decider_ = std::make_unique<lite_video::LiteVideoDecider>(
+        nullptr, &test_clock_, nullptr);
 
     lite_video_decider_->OnEffectiveConnectionTypeChanged(
         net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
@@ -96,6 +165,13 @@
         "enable-spdy-proxy-auth");
   }
 
+  void UseOptimizationGuideDecider() {
+    optimization_guide_decider_->RegisterOptimizationTypes(
+        {optimization_guide::proto::LITE_VIDEO});
+    lite_video_decider_->SetOptimizationGuideDeciderForTesting(
+        optimization_guide_decider_.get());
+  }
+
   void DisableLiteVideo() {
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitAndDisableFeature({::features::kLiteVideo});
@@ -115,11 +191,52 @@
                        base::Unretained(this)));
   }
 
+  void SetDurationFromTimeDelta(optimization_guide::proto::Duration* duration,
+                                const base::TimeDelta& delta) {
+    if (!duration)
+      return;
+    duration->set_seconds(delta.InSeconds());
+    duration->set_nanos(delta.InNanoseconds() %
+                        base::TimeDelta::FromSeconds(1).InNanoseconds());
+  }
+
   void SeedLiteVideoHintCache(const GURL& gurl,
-                              lite_video::LiteVideoHint hint) {
+                              base::Optional<lite_video::LiteVideoHint> hint,
+                              bool use_opt_guide) {
+    if (use_opt_guide) {
+      optimization_guide::OptimizationMetadata default_metadata;
+      optimization_guide::proto::LiteVideoMetadata lite_video_metadata;
+      if (hint) {
+        optimization_guide::proto::LiteVideoHint* hint_proto =
+            lite_video_metadata.mutable_lite_video_hint();
+        hint_proto->set_target_downlink_bandwidth_kbps(
+            hint->target_downlink_bandwidth_kbps());
+        hint_proto->set_kilobytes_to_buffer_before_throttle(
+            hint->kilobytes_to_buffer_before_throttle());
+        SetDurationFromTimeDelta(
+            hint_proto->mutable_target_downlink_rtt_latency(),
+            hint->target_downlink_rtt_latency());
+        SetDurationFromTimeDelta(hint_proto->mutable_max_throttling_delay(),
+                                 hint->max_throttling_delay());
+        default_metadata.SetAnyMetadataForTesting(lite_video_metadata);
+      }
+
+      std::map<std::tuple<GURL, optimization_guide::proto::OptimizationType>,
+               std::tuple<optimization_guide::OptimizationGuideDecision,
+                          optimization_guide::OptimizationMetadata>>
+          responses = {
+              {std::make_tuple(gurl, optimization_guide::proto::LITE_VIDEO),
+               std::make_tuple(
+                   optimization_guide::OptimizationGuideDecision::kTrue,
+                   default_metadata)},
+          };
+
+      optimization_guide_decider_->SetResponses(responses);
+      return;
+    }
     std::unique_ptr<TestLiteVideoHintCache> hint_cache =
         std::make_unique<TestLiteVideoHintCache>();
-    hint_cache->AddHintForTesting(gurl, hint);
+    hint_cache->AddHintForTesting(gurl, *hint);
     lite_video_decider_->SetHintCacheForTesting(std::move(hint_cache));
   }
 
@@ -135,14 +252,21 @@
     return lite_video_decider_.get();
   }
 
-  void OnHintAvailable(base::Optional<lite_video::LiteVideoHint> hint,
-                       lite_video::LiteVideoBlocklistReason blocklist_reason) {
+  void OnHintAvailable(
+      base::Optional<lite_video::LiteVideoHint> hint,
+      lite_video::LiteVideoBlocklistReason blocklist_reason,
+      optimization_guide::OptimizationGuideDecision opt_guide_decision) {
+    opt_guide_decision_ = opt_guide_decision;
     hint_ = hint;
     blocklist_reason_ = blocklist_reason;
   }
 
   base::Optional<lite_video::LiteVideoHint> hint() { return hint_; }
 
+  optimization_guide::OptimizationGuideDecision opt_guide_decision() {
+    return opt_guide_decision_;
+  }
+
   lite_video::LiteVideoBlocklistReason blocklist_reason() {
     return blocklist_reason_;
   }
@@ -160,6 +284,8 @@
   std::unique_ptr<lite_video::LiteVideoDecider> lite_video_decider_;
   lite_video::LiteVideoBlocklistReason blocklist_reason_;
   base::Optional<lite_video::LiteVideoHint> hint_;
+  std::unique_ptr<TestOptimizationGuideDecider> optimization_guide_decider_;
+  optimization_guide::OptimizationGuideDecision opt_guide_decision_;
 };
 
 TEST_F(LiteVideoDeciderTest, CanApplyOnNonHTTPOrHTTPSURL) {
@@ -239,7 +365,7 @@
       /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
       /*kilobytes_to_buffer_before_throttle=*/500,
       /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
-  SeedLiteVideoHintCache(url, seeded_hint);
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
 
   lite_video_decider()->CanApplyLiteVideo(
       &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
@@ -276,7 +402,7 @@
       /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
       /*kilobytes_to_buffer_before_throttle=*/500,
       /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
-  SeedLiteVideoHintCache(url, seeded_hint);
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
 
   lite_video_decider()->CanApplyLiteVideo(
       &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
@@ -304,7 +430,7 @@
       /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
       /*kilobytes_to_buffer_before_throttle=*/500,
       /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
-  SeedLiteVideoHintCache(url, seeded_hint);
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
 
   CanApplyOnSubframeNavigation(GURL("https://mainframe.com"), url);
   ASSERT_TRUE(hint());
@@ -339,7 +465,7 @@
       /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
       /*kilobytes_to_buffer_before_throttle=*/500,
       /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
-  SeedLiteVideoHintCache(url, seeded_hint);
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
 
   lite_video_decider()->CanApplyLiteVideo(
       &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
@@ -370,7 +496,7 @@
       /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
       /*kilobytes_to_buffer_before_throttle=*/500,
       /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
-  SeedLiteVideoHintCache(url, seeded_hint);
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/false);
 
   lite_video_decider()->CanApplyLiteVideo(
       &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
@@ -406,3 +532,206 @@
   ASSERT_TRUE(hint());
   EXPECT_EQ(200, hint()->target_downlink_bandwidth_kbps());
 }
+
+TEST_F(LiteVideoDeciderTest, OptimizationGuide_CanApplyLiteVideo) {
+  base::HistogramTester histogram_tester;
+  UseOptimizationGuideDecider();
+
+  SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
+  GURL url("https://LiteVideo.com");
+  content::MockNavigationHandle navigation_handle(web_contents());
+  navigation_handle.set_url(url);
+  navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  lite_video::LiteVideoHint seeded_hint(
+      /*target_downlink_bandwidth_kbps=*/123,
+      /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
+      /*kilobytes_to_buffer_before_throttle=*/500,
+      /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
+  SeedLiteVideoHintCache(url, seeded_hint, /*use_opt_guide=*/true);
+
+  lite_video_decider()->CanApplyLiteVideo(
+      &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
+                                         base::Unretained(this)));
+  RunUntilIdle();
+
+  ASSERT_TRUE(hint());
+  EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
+  EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
+            hint()->target_downlink_bandwidth_kbps());
+  EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
+            hint()->target_downlink_rtt_latency());
+  EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
+            hint()->kilobytes_to_buffer_before_throttle());
+  EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectTotalCount(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
+}
+
+TEST_F(LiteVideoDeciderTest, OptimizationGuide_NoMetadata_CanApplyLiteVideo) {
+  base::HistogramTester histogram_tester;
+  UseOptimizationGuideDecider();
+
+  SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
+  GURL url("https://LiteVideo.com");
+  content::MockNavigationHandle navigation_handle(web_contents());
+  navigation_handle.set_url(url);
+  navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  SeedLiteVideoHintCache(url, /*hint=*/base::nullopt, /*use_opt_guide=*/true);
+
+  lite_video_decider()->CanApplyLiteVideo(
+      &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
+                                         base::Unretained(this)));
+  RunUntilIdle();
+
+  ASSERT_TRUE(hint());
+  EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
+  EXPECT_EQ(lite_video::switches::GetDefaultDownlinkBandwidthKbps(),
+            hint()->target_downlink_bandwidth_kbps());
+  EXPECT_EQ(lite_video::features::LiteVideoTargetDownlinkRTTLatency(),
+            hint()->target_downlink_rtt_latency());
+  EXPECT_EQ(lite_video::features::LiteVideoKilobytesToBufferBeforeThrottle(),
+            hint()->kilobytes_to_buffer_before_throttle());
+  EXPECT_EQ(lite_video::features::LiteVideoMaxThrottlingDelay(),
+            hint()->max_throttling_delay());
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectTotalCount(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 1);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
+}
+
+TEST_F(LiteVideoDeciderTest, OptimizationGuide_CanApplyOnSubframeNavigation) {
+  base::HistogramTester histogram_tester;
+  UseOptimizationGuideDecider();
+
+  SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
+  GURL url("https://LiteVideo.com");
+  GURL mainframe_url("https://mainframe.com");
+  content::MockNavigationHandle navigation_handle(web_contents());
+  navigation_handle.set_url(mainframe_url);
+  navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+  lite_video::LiteVideoHint seeded_hint(
+      /*target_downlink_bandwidth_kbps=*/123,
+      /*target_downlink_rtt_latency=*/base::TimeDelta::FromMilliseconds(2500),
+      /*kilobytes_to_buffer_before_throttle=*/500,
+      /*max_throttling_delay=*/base::TimeDelta::FromMilliseconds(5000));
+  SeedLiteVideoHintCache(mainframe_url, seeded_hint, /*use_opt_guide=*/true);
+
+  // Force a check on the mainframe, otherwise no hint will be set for the
+  // subframe.
+  lite_video_decider()->CanApplyLiteVideo(
+      &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
+                                         base::Unretained(this)));
+  RunUntilIdle();
+
+  CanApplyOnSubframeNavigation(mainframe_url, url);
+  RunUntilIdle();
+
+  ASSERT_TRUE(hint());
+  EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
+  EXPECT_EQ(opt_guide_decision(),
+            optimization_guide::OptimizationGuideDecision::kTrue);
+  EXPECT_EQ(seeded_hint.target_downlink_bandwidth_kbps(),
+            hint()->target_downlink_bandwidth_kbps());
+  EXPECT_EQ(seeded_hint.target_downlink_rtt_latency(),
+            hint()->target_downlink_rtt_latency());
+  EXPECT_EQ(seeded_hint.kilobytes_to_buffer_before_throttle(),
+            hint()->kilobytes_to_buffer_before_throttle());
+  EXPECT_EQ(seeded_hint.max_throttling_delay(), hint()->max_throttling_delay());
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectTotalCount(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 1);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.HintCache.HasHint", true, 2);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
+}
+
+TEST_F(LiteVideoDeciderTest,
+       OptimizationGuide_CanApplyOnSubframeNavigation_Unknown) {
+  base::HistogramTester histogram_tester;
+  UseOptimizationGuideDecider();
+
+  SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
+  GURL url("https://LiteVideo.com");
+  GURL mainframe_url("https://mainframe.com");
+  content::MockNavigationHandle navigation_handle(web_contents());
+  navigation_handle.set_url(mainframe_url);
+  navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+
+  SeedLiteVideoHintCache(mainframe_url, base::nullopt, /*use_opt_guide=*/true);
+
+  CanApplyOnSubframeNavigation(mainframe_url, url);
+  RunUntilIdle();
+
+  EXPECT_FALSE(hint());
+  EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
+  EXPECT_EQ(opt_guide_decision(),
+            optimization_guide::OptimizationGuideDecision::kUnknown);
+
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectTotalCount(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame", 0);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 1);
+  histogram_tester.ExpectTotalCount(
+      "LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 0);
+}
+
+TEST_F(LiteVideoDeciderTest,
+       OptimizationGuide_CanApplyOnSubframeNavigation_MainframeFalse) {
+  base::HistogramTester histogram_tester;
+  UseOptimizationGuideDecider();
+
+  SetBlocklistReason(lite_video::LiteVideoBlocklistReason::kAllowed);
+  GURL subframe_url("https://LiteVideo.com");
+  GURL mainframe_url("https://mainframe.com");
+  content::MockNavigationHandle navigation_handle(web_contents());
+  navigation_handle.set_url(mainframe_url);
+  navigation_handle.set_page_transition(ui::PAGE_TRANSITION_TYPED);
+
+  SeedLiteVideoHintCache(subframe_url, base::nullopt, /*use_opt_guide=*/true);
+
+  // Force a check on the mainframe, otherwise no hint will be set for the
+  // subframe.
+  lite_video_decider()->CanApplyLiteVideo(
+      &navigation_handle, base::BindOnce(&LiteVideoDeciderTest::OnHintAvailable,
+                                         base::Unretained(this)));
+  RunUntilIdle();
+  ASSERT_FALSE(hint());
+  EXPECT_EQ(opt_guide_decision(),
+            optimization_guide::OptimizationGuideDecision::kFalse);
+
+  CanApplyOnSubframeNavigation(mainframe_url, subframe_url);
+  RunUntilIdle();
+
+  ASSERT_FALSE(hint());
+  EXPECT_EQ(blocklist_reason(), lite_video::LiteVideoBlocklistReason::kAllowed);
+  EXPECT_EQ(opt_guide_decision(),
+            optimization_guide::OptimizationGuideDecision::kFalse);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.UserBlocklist.MainFrame",
+      lite_video::LiteVideoBlocklistReason::kAllowed, 1);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.CanApplyLiteVideo.HintCache.HasHint", false, 2);
+  histogram_tester.ExpectUniqueSample(
+      "LiteVideo.LiteVideoDecider.OptGuideHintCacheSize", 1, 1);
+}
diff --git a/chrome/browser/lite_video/lite_video_features.cc b/chrome/browser/lite_video/lite_video_features.cc
index 5491473..c637d52 100644
--- a/chrome/browser/lite_video/lite_video_features.cc
+++ b/chrome/browser/lite_video/lite_video_features.cc
@@ -26,6 +26,11 @@
                                                  "is_coinflip_exp", false);
 }
 
+bool LiteVideoUseOptimizationGuide() {
+  return base::GetFieldTrialParamByFeatureAsBool(
+      ::features::kLiteVideo, "use_optimization_guide", false);
+}
+
 base::Optional<base::Value> GetLiteVideoOriginHintsFromFieldTrial() {
   if (!IsLiteVideoEnabled())
     return base::nullopt;
@@ -87,5 +92,12 @@
       .value_or(net::EFFECTIVE_CONNECTION_TYPE_4G);
 }
 
+int MaxOptimizationGuideHintCacheSize() {
+  return LiteVideoUseOptimizationGuide()
+             ? GetFieldTrialParamByFeatureAsInt(
+                   ::features::kLiteVideo, "max_opt_guide_hint_cache_size", 10)
+             : 1;
+}
+
 }  // namespace features
 }  // namespace lite_video
diff --git a/chrome/browser/lite_video/lite_video_features.h b/chrome/browser/lite_video/lite_video_features.h
index 68957929..adc181c 100644
--- a/chrome/browser/lite_video/lite_video_features.h
+++ b/chrome/browser/lite_video/lite_video_features.h
@@ -25,6 +25,9 @@
 // should be heldback on a per navigation basis.
 bool IsCoinflipExperimentEnabled();
 
+// Whether LiteVideo should rely on the optimization guide for hints.
+bool LiteVideoUseOptimizationGuide();
+
 // Return the origins that are whitelisted for using the LiteVideo optimization
 // and the parameters needed to throttle media requests for that origin.
 base::Optional<base::Value> GetLiteVideoOriginHintsFromFieldTrial();
@@ -58,6 +61,10 @@
 // on.
 net::EffectiveConnectionType MinLiteVideoECT();
 
+// The maximum number of hints the LiteVideoDecider should cache locally
+// for reuse by subframes.
+int MaxOptimizationGuideHintCacheSize();
+
 }  // namespace features
 }  // namespace lite_video
 
diff --git a/chrome/browser/lite_video/lite_video_hint.cc b/chrome/browser/lite_video/lite_video_hint.cc
index 7dd8bec..e3cc2b3 100644
--- a/chrome/browser/lite_video/lite_video_hint.cc
+++ b/chrome/browser/lite_video/lite_video_hint.cc
@@ -4,6 +4,23 @@
 
 #include "chrome/browser/lite_video/lite_video_hint.h"
 
+#include "chrome/browser/lite_video/lite_video_features.h"
+#include "chrome/browser/lite_video/lite_video_switches.h"
+
+namespace {
+
+base::TimeDelta GetTimeDeltaFromDuration(
+    const optimization_guide::proto::Duration& duration) {
+  base::TimeDelta delta;
+  if (duration.has_seconds())
+    delta += base::TimeDelta::FromSeconds(duration.seconds());
+  if (duration.has_nanos())
+    delta += base::TimeDelta::FromNanoseconds(duration.nanos());
+  return delta;
+}
+
+}  // namespace
+
 namespace lite_video {
 
 LiteVideoHint::LiteVideoHint(int target_downlink_bandwidth_kbps,
@@ -15,4 +32,23 @@
       kilobytes_to_buffer_before_throttle_(kilobytes_to_buffer_before_throttle),
       max_throttling_delay_(max_throttling_delay) {}
 
+LiteVideoHint::LiteVideoHint(
+    const optimization_guide::proto::LiteVideoHint& hint_proto) {
+  target_downlink_bandwidth_kbps_ =
+      hint_proto.has_target_downlink_bandwidth_kbps()
+          ? hint_proto.target_downlink_bandwidth_kbps()
+          : switches::GetDefaultDownlinkBandwidthKbps();
+  target_downlink_rtt_latency_ =
+      hint_proto.has_target_downlink_rtt_latency()
+          ? GetTimeDeltaFromDuration(hint_proto.target_downlink_rtt_latency())
+          : features::LiteVideoTargetDownlinkRTTLatency();
+  kilobytes_to_buffer_before_throttle_ =
+      hint_proto.has_kilobytes_to_buffer_before_throttle()
+          ? hint_proto.kilobytes_to_buffer_before_throttle()
+          : features::LiteVideoKilobytesToBufferBeforeThrottle();
+  max_throttling_delay_ =
+      hint_proto.has_max_throttling_delay()
+          ? GetTimeDeltaFromDuration(hint_proto.max_throttling_delay())
+          : features::LiteVideoMaxThrottlingDelay();
+}
 }  // namespace lite_video
diff --git a/chrome/browser/lite_video/lite_video_hint.h b/chrome/browser/lite_video/lite_video_hint.h
index 3fc6b18..c7e6afb4 100644
--- a/chrome/browser/lite_video/lite_video_hint.h
+++ b/chrome/browser/lite_video/lite_video_hint.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include "base/time/time.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
 
 namespace lite_video {
 
@@ -17,6 +18,9 @@
                 base::TimeDelta target_downlink_rtt_latency,
                 int kilobytes_to_buffer_before_throttle,
                 base::TimeDelta max_throttling_delay);
+  // This uses default values for any empty fields in |lite_video_hint|.
+  explicit LiteVideoHint(
+      const optimization_guide::proto::LiteVideoHint& lite_video_hint);
   ~LiteVideoHint() = default;
 
   int target_downlink_bandwidth_kbps() const {
diff --git a/chrome/browser/lite_video/lite_video_hint_unittest.cc b/chrome/browser/lite_video/lite_video_hint_unittest.cc
new file mode 100644
index 0000000..e992629
--- /dev/null
+++ b/chrome/browser/lite_video/lite_video_hint_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lite_video/lite_video_hint.h"
+
+#include "base/time/time.h"
+#include "chrome/browser/lite_video/lite_video_features.h"
+#include "chrome/browser/lite_video/lite_video_switches.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+void SetDurationFromTimeDelta(optimization_guide::proto::Duration* duration,
+                              const base::TimeDelta& delta) {
+  if (!duration)
+    return;
+  duration->set_seconds(delta.InSeconds());
+  duration->set_nanos(delta.InNanoseconds() %
+                      base::TimeDelta::FromSeconds(1).InNanoseconds());
+}
+
+TEST(LiteVideoHintTest, OptGuideMetadataHint) {
+  optimization_guide::proto::LiteVideoHint hint_proto;
+  base::TimeDelta throttle_delay =
+      base::TimeDelta::FromSeconds(5) + base::TimeDelta::FromNanoseconds(5);
+  hint_proto.set_target_downlink_bandwidth_kbps(100);
+  hint_proto.set_kilobytes_to_buffer_before_throttle(10);
+  SetDurationFromTimeDelta(hint_proto.mutable_target_downlink_rtt_latency(),
+                           base::TimeDelta::FromSeconds(5));
+  SetDurationFromTimeDelta(hint_proto.mutable_max_throttling_delay(),
+                           throttle_delay);
+  lite_video::LiteVideoHint hint(hint_proto);
+  EXPECT_EQ(hint.target_downlink_bandwidth_kbps(), 100);
+  EXPECT_EQ(hint.kilobytes_to_buffer_before_throttle(), 10);
+  EXPECT_EQ(hint.target_downlink_rtt_latency(),
+            base::TimeDelta::FromSeconds(5));
+  EXPECT_EQ(hint.max_throttling_delay(), throttle_delay);
+}
+
+TEST(LiteVideoHintTest, OptGuideMetadataHint_MissingFields) {
+  optimization_guide::proto::LiteVideoHint hint_proto;
+
+  lite_video::LiteVideoHint hint(hint_proto);
+  EXPECT_EQ(hint.target_downlink_bandwidth_kbps(),
+            lite_video::switches::GetDefaultDownlinkBandwidthKbps());
+  EXPECT_EQ(hint.kilobytes_to_buffer_before_throttle(),
+            lite_video::features::LiteVideoKilobytesToBufferBeforeThrottle());
+  EXPECT_EQ(hint.target_downlink_rtt_latency(),
+            lite_video::features::LiteVideoTargetDownlinkRTTLatency());
+  EXPECT_EQ(hint.max_throttling_delay(),
+            lite_video::features::LiteVideoMaxThrottlingDelay());
+}
diff --git a/chrome/browser/lite_video/lite_video_keyed_service.cc b/chrome/browser/lite_video/lite_video_keyed_service.cc
index 7edeab4..93bb19d 100644
--- a/chrome/browser/lite_video/lite_video_keyed_service.cc
+++ b/chrome/browser/lite_video/lite_video_keyed_service.cc
@@ -12,7 +12,11 @@
 #include "base/time/default_clock.h"
 #include "chrome/browser/lite_video/lite_video_decider.h"
 #include "chrome/browser/lite_video/lite_video_features.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "components/blocklist/opt_out_blocklist/sql/opt_out_store_sql.h"
+#include "components/optimization_guide/optimization_guide_decider.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -21,7 +25,8 @@
     FILE_PATH_LITERAL("lite_video_opt_out.db");
 
 LiteVideoKeyedService::LiteVideoKeyedService(
-    content::BrowserContext* browser_context) {}
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {}
 
 LiteVideoKeyedService::~LiteVideoKeyedService() = default;
 
@@ -39,12 +44,19 @@
       base::CreateSingleThreadTaskRunner({content::BrowserThread::UI}),
       background_task_runner, profile_path.Append(kLiteVideoOptOutDBFilename));
 
+  optimization_guide::OptimizationGuideDecider* opt_guide_decider = nullptr;
+  if (lite_video::features::LiteVideoUseOptimizationGuide()) {
+    opt_guide_decider = OptimizationGuideKeyedServiceFactory::GetForProfile(
+        Profile::FromBrowserContext(browser_context_));
+  }
+
   decider_ = std::make_unique<lite_video::LiteVideoDecider>(
-      std::move(opt_out_store), base::DefaultClock::GetInstance());
+      std::move(opt_out_store), base::DefaultClock::GetInstance(),
+      opt_guide_decider);
 }
 
 void LiteVideoKeyedService::ClearData(const base::Time& delete_begin,
                                       const base::Time& delete_end) {
   if (decider_)
-    decider_->ClearBlocklist(delete_begin, delete_end);
+    decider_->ClearData(delete_begin, delete_end);
 }
diff --git a/chrome/browser/lite_video/lite_video_keyed_service.h b/chrome/browser/lite_video/lite_video_keyed_service.h
index 46efe816..7aa260f 100644
--- a/chrome/browser/lite_video/lite_video_keyed_service.h
+++ b/chrome/browser/lite_video/lite_video_keyed_service.h
@@ -44,6 +44,9 @@
   // The decider owned by this keyed service capable of determining whether
   // to apply the LiteVideo optimization to a navigation.
   std::unique_ptr<lite_video::LiteVideoDecider> decider_;
+
+  // Guaranteed to outlive |this|.
+  content::BrowserContext* browser_context_;
 };
 
 #endif  // CHROME_BROWSER_LITE_VIDEO_LITE_VIDEO_KEYED_SERVICE_H_
diff --git a/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc b/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
index 02a7970..b6b5af0f 100644
--- a/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
+++ b/chrome/browser/lite_video/lite_video_keyed_service_browsertest.cc
@@ -16,12 +16,18 @@
 #include "chrome/browser/lite_video/lite_video_keyed_service_factory.h"
 #include "chrome/browser/lite_video/lite_video_observer.h"
 #include "chrome/browser/lite_video/lite_video_switches.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/metrics/content/subprocess_metrics_provider.h"
+#include "components/optimization_guide/optimization_guide_decider.h"
+#include "components/optimization_guide/optimization_guide_features.h"
+#include "components/optimization_guide/proto/hints.pb.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test.h"
@@ -106,17 +112,26 @@
 }
 
 class LiteVideoKeyedServiceBrowserTest
-    : public LiteVideoKeyedServiceDisabledBrowserTest {
+    : public LiteVideoKeyedServiceDisabledBrowserTest,
+      public ::testing::WithParamInterface<bool> {
  public:
-  LiteVideoKeyedServiceBrowserTest() = default;
+  LiteVideoKeyedServiceBrowserTest() : use_opt_guide_(GetParam()) {}
   ~LiteVideoKeyedServiceBrowserTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-        {::features::kLiteVideo},
-        {{"lite_video_origin_hints", "{\"litevideo.com\": 123}"},
-         {"user_blocklist_opt_out_history_threshold", "1"}});
-
+    if (use_opt_guide_) {
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{::features::kLiteVideo,
+            {{"use_optimization_guide", "true"},
+             {"user_blocklist_opt_out_history_threshold", "1"}}},
+           {optimization_guide::features::kOptimizationHints, {}}},
+          /*disabled_features=*/{});
+    } else {
+      scoped_feature_list_.InitAndEnableFeatureWithParameters(
+          {::features::kLiteVideo},
+          {{"lite_video_origin_hints", "{\"litevideo.com\": 123}"},
+           {"user_blocklist_opt_out_history_threshold", "1"}});
+    }
     SetUpHTTPSServer();
     InProcessBrowserTest::SetUp();
   }
@@ -126,6 +141,8 @@
         network::mojom::ConnectionType::CONNECTION_4G);
     SetEffectiveConnectionType(
         net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
+    if (use_opt_guide_)
+      SeedOptGuideLiteVideoHints(GURL("https://litevideo.com"));
     InProcessBrowserTest::SetUpOnMainThread();
   }
 
@@ -144,6 +161,19 @@
     ASSERT_TRUE(https_url().SchemeIs(url::kHttpsScheme));
   }
 
+  // Sets up public image URL hint data.
+  void SeedOptGuideLiteVideoHints(const GURL& url) {
+    ASSERT_TRUE(use_opt_guide_);
+    auto* optimization_guide_decider =
+        OptimizationGuideKeyedServiceFactory::GetForProfile(
+            browser()->profile());
+    optimization_guide::OptimizationMetadata optimization_metadata;
+    optimization_guide::proto::LiteVideoMetadata metadata;
+    optimization_metadata.SetAnyMetadataForTesting(metadata);
+    optimization_guide_decider->AddHintForTesting(
+        url, optimization_guide::proto::LITE_VIDEO, optimization_metadata);
+  }
+
   // Sets the effective connection type that the Network Quality Tracker will
   // report.
   void SetEffectiveConnectionType(
@@ -168,20 +198,28 @@
 
   GURL https_url() { return https_url_; }
 
+  bool IsUsingOptGuide() { return use_opt_guide_; }
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<net::EmbeddedTestServer> https_server_;
   GURL https_url_;
   base::HistogramTester histogram_tester_;
+  const bool use_opt_guide_ = false;
 };
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+INSTANTIATE_TEST_SUITE_P(UsingOptGuide,
+                         LiteVideoKeyedServiceBrowserTest,
+                         ::testing::Bool(),
+                         ::testing::PrintToStringParamName());
+
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoEnabledWithKeyedService) {
   EXPECT_TRUE(
       LiteVideoKeyedServiceFactory::GetForProfile(browser()->profile()));
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_UnsupportedScheme) {
   WaitForBlocklistToBeLoaded();
   ukm::TestAutoSetUkmRecorder ukm_recorder;
@@ -209,7 +247,7 @@
 #define MAYBE_LiteVideoCanApplyLiteVideo_NoHintForHost \
   LiteVideoCanApplyLiteVideo_NoHintForHost
 #endif
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        MAYBE_LiteVideoCanApplyLiteVideo_NoHintForHost) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   SetEffectiveConnectionType(
@@ -252,11 +290,12 @@
           lite_video::LiteVideoThrottleResult::kThrottledWithoutStop));
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_HasHint) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   SetEffectiveConnectionType(
       net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_4G);
+
   WaitForBlocklistToBeLoaded();
   EXPECT_TRUE(
       LiteVideoKeyedServiceFactory::GetForProfile(browser()->profile()));
@@ -298,7 +337,7 @@
           lite_video::LiteVideoThrottleResult::kThrottledWithoutStop));
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_Reload) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   WaitForBlocklistToBeLoaded();
@@ -375,7 +414,7 @@
           lite_video::LiteVideoThrottleResult::kThrottledWithoutStop));
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_ForwardBack) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   WaitForBlocklistToBeLoaded();
@@ -452,7 +491,7 @@
           lite_video::LiteVideoThrottleResult::kThrottledWithoutStop));
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        MultipleNavigationsNotBlocklisted) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   WaitForBlocklistToBeLoaded();
@@ -523,7 +562,7 @@
 #define DISABLE_ON_WIN(x) x
 #endif
 
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     LiteVideoKeyedServiceBrowserTest,
     DISABLE_ON_WIN(UserBlocklistClearedOnBrowserHistoryClear)) {
   WaitForBlocklistToBeLoaded();
@@ -569,6 +608,11 @@
   // Wipe the browser history, clearing the user blocklist.
   // This should allow LiteVideos on the next navigation.
   browser()->profile()->Wipe();
+  if (IsUsingOptGuide()) {
+    // Browser clear wipes the Optimization Guide hint store so
+    // we need to re-seed the hints.
+    SeedOptGuideLiteVideoHints(url);
+  }
 
   EXPECT_GT(
       RetryForHistogramUntilCountReached(
@@ -594,18 +638,25 @@
 class LiteVideoNetworkConnectionBrowserTest
     : public LiteVideoKeyedServiceBrowserTest {
  public:
-  LiteVideoNetworkConnectionBrowserTest() = default;
+  LiteVideoNetworkConnectionBrowserTest() : use_opt_guide_(GetParam()) {}
   ~LiteVideoNetworkConnectionBrowserTest() override = default;
 
   void SetUpCommandLine(base::CommandLine* cmd) override {
+    // This removes the network override switch.
     cmd->AppendSwitch("enable-spdy-proxy-auth");
   }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
+  const bool use_opt_guide_ = false;
 };
 
-IN_PROC_BROWSER_TEST_F(LiteVideoNetworkConnectionBrowserTest,
+INSTANTIATE_TEST_SUITE_P(UsingOptGuide,
+                         LiteVideoNetworkConnectionBrowserTest,
+                         ::testing::Bool(),
+                         ::testing::PrintToStringParamName());
+
+IN_PROC_BROWSER_TEST_P(LiteVideoNetworkConnectionBrowserTest,
                        LiteVideoCanApplyLiteVideo_NetworkNotCellular) {
   WaitForBlocklistToBeLoaded();
   EXPECT_TRUE(
@@ -631,7 +682,7 @@
       "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
 }
 
-IN_PROC_BROWSER_TEST_F(
+IN_PROC_BROWSER_TEST_P(
     LiteVideoNetworkConnectionBrowserTest,
     LiteVideoCanApplyLiteVideo_NetworkConnectionBelowMinECT) {
   WaitForBlocklistToBeLoaded();
@@ -659,7 +710,7 @@
       "LiteVideo.CanApplyLiteVideo.UserBlocklist.SubFrame", 0);
 }
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceBrowserTest,
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceBrowserTest,
                        LiteVideoCanApplyLiteVideo_NavigationWithSubframe) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
   SetEffectiveConnectionType(
@@ -706,21 +757,35 @@
 class LiteVideoKeyedServiceCoinflipBrowserTest
     : public LiteVideoKeyedServiceBrowserTest {
  public:
-  LiteVideoKeyedServiceCoinflipBrowserTest() = default;
+  LiteVideoKeyedServiceCoinflipBrowserTest() : use_opt_guide_(GetParam()) {}
   ~LiteVideoKeyedServiceCoinflipBrowserTest() override = default;
 
   void SetUp() override {
-    scoped_feature_list_.InitAndEnableFeatureWithParameters(
-        {::features::kLiteVideo}, {{"is_coinflip_exp", "true"}});
+    if (use_opt_guide_) {
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{::features::kLiteVideo,
+            {{"use_optimization_guide", "true"}, {"is_coinflip_exp", "true"}}},
+           {optimization_guide::features::kOptimizationHints, {}}},
+          /*disabled_features=*/{});
+    } else {
+      scoped_feature_list_.InitAndEnableFeatureWithParameters(
+          {::features::kLiteVideo}, {{"is_coinflip_exp", "true"}});
+    }
     SetUpHTTPSServer();
     InProcessBrowserTest::SetUp();
   }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
+  const bool use_opt_guide_ = false;
 };
 
-IN_PROC_BROWSER_TEST_F(LiteVideoKeyedServiceCoinflipBrowserTest,
+INSTANTIATE_TEST_SUITE_P(UsingOptGuide,
+                         LiteVideoKeyedServiceCoinflipBrowserTest,
+                         ::testing::Bool(),
+                         ::testing::PrintToStringParamName());
+
+IN_PROC_BROWSER_TEST_P(LiteVideoKeyedServiceCoinflipBrowserTest,
                        LiteVideoCanApplyLiteVideo_CoinflipHoldback) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       lite_video::switches::kLiteVideoForceOverrideDecision);
diff --git a/chrome/browser/lite_video/lite_video_observer.cc b/chrome/browser/lite_video/lite_video_observer.cc
index ab4a12ec..2ba52f1 100644
--- a/chrome/browser/lite_video/lite_video_observer.cc
+++ b/chrome/browser/lite_video/lite_video_observer.cc
@@ -17,7 +17,11 @@
 #include "chrome/browser/lite_video/lite_video_switches.h"
 #include "chrome/browser/lite_video/lite_video_user_blocklist.h"
 #include "chrome/browser/lite_video/lite_video_util.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service.h"
+#include "chrome/browser/optimization_guide/optimization_guide_keyed_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "components/optimization_guide/optimization_guide_decider.h"
+#include "components/optimization_guide/proto/lite_video_metadata.pb.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -62,6 +66,7 @@
 LiteVideoObserver::LiteVideoObserver(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {
   lite_video_decider_ = GetLiteVideoDeciderFromWebContents(web_contents);
+  routing_ids_to_notify_ = {};
 }
 
 LiteVideoObserver::~LiteVideoObserver() {
@@ -86,6 +91,7 @@
 
   if (navigation_handle->IsInMainFrame()) {
     FlushUKMMetrics();
+    routing_ids_to_notify_.clear();
     nav_metrics_ = lite_video::LiteVideoNavigationMetrics(
         navigation_handle->GetNavigationId(),
         lite_video::LiteVideoDecision::kUnknown, blocklist_reason,
@@ -96,6 +102,7 @@
   auto* render_frame_host = navigation_handle->GetRenderFrameHost();
   if (!render_frame_host)
     return;
+
   lite_video_decider_->CanApplyLiteVideo(
       navigation_handle,
       base::BindOnce(&LiteVideoObserver::OnHintAvailable,
@@ -106,26 +113,44 @@
 }
 
 void LiteVideoObserver::OnHintAvailable(
-    content::GlobalFrameRoutingId render_frame_host_routing_id,
+    const content::GlobalFrameRoutingId& render_frame_host_routing_id,
     base::Optional<lite_video::LiteVideoHint> hint,
-    lite_video::LiteVideoBlocklistReason blocklist_reason) {
+    lite_video::LiteVideoBlocklistReason blocklist_reason,
+    optimization_guide::OptimizationGuideDecision opt_guide_decision) {
   auto* render_frame_host =
       content::RenderFrameHost::FromID(render_frame_host_routing_id);
   if (!render_frame_host)
     return;
 
+  bool is_mainframe = render_frame_host->GetMainFrame() == render_frame_host;
+  if (!is_mainframe &&
+      opt_guide_decision ==
+          optimization_guide::OptimizationGuideDecision::kUnknown) {
+    // If this is a subframe and the decision was unknown, then the decision
+    // from the optimization guide (queried only for the mainframe) has not
+    // returned.
+    //
+    // TODO(crbug/1121833): Add histogram to capture the size of the set of
+    // routing ids.
+    routing_ids_to_notify_.insert(render_frame_host_routing_id);
+    return;
+  }
   lite_video::LiteVideoDecision decision = MakeLiteVideoDecision(hint);
 
   LOCAL_HISTOGRAM_BOOLEAN("LiteVideo.Navigation.HasHint", hint ? true : false);
-
-  if (nav_metrics_ && render_frame_host->GetMainFrame()) {
+  // TODO(crbug/1117064): Add a global blocklist check to ensure that the host
+  // commited of the committed URL is allowed to have LiteVideos applied.
+  if (nav_metrics_ && is_mainframe) {
     nav_metrics_->SetDecision(decision);
     nav_metrics_->SetBlocklistReason(blocklist_reason);
   }
 
   // Only proceed to passing hints if the decision is allowed.
-  if (decision != lite_video::LiteVideoDecision::kAllowed)
+  if (decision != lite_video::LiteVideoDecision::kAllowed &&
+      opt_guide_decision !=
+          optimization_guide::OptimizationGuideDecision::kTrue) {
     return;
+  }
 
   if (!hint)
     return;
@@ -133,16 +158,41 @@
   if (!render_frame_host || !render_frame_host->GetProcess())
     return;
 
+  // At this stage, the following criteria for the render frame should be true:
+  // 1. The render frame for the routing id is valid.
+  // 2. The current navigation within the frame is not blocked.
+  // 3. The decision to apply a LiteVideo is true.
+  // 4. A LiteVideo hint is available.
+  SendHintToRenderFrameAgentForID(render_frame_host_routing_id, *hint);
+
+  if (is_mainframe) {
+    // Given that this is the mainframe, we need to notify all the subframes
+    // that have requested LiteVideo hints but the optimization guide had
+    // not returned a decision.
+    for (const auto& routing_id : routing_ids_to_notify_)
+      SendHintToRenderFrameAgentForID(routing_id, *hint);
+    routing_ids_to_notify_.clear();
+    return;
+  }
+}
+
+void LiteVideoObserver::SendHintToRenderFrameAgentForID(
+    const content::GlobalFrameRoutingId& routing_id,
+    const lite_video::LiteVideoHint& hint) {
+  auto* render_frame_host = content::RenderFrameHost::FromID(routing_id);
+  if (!render_frame_host)
+    return;
+
   mojo::AssociatedRemote<blink::mojom::PreviewsResourceLoadingHintsReceiver>
       loading_hints_agent;
 
   auto hint_ptr = blink::mojom::LiteVideoHint::New();
   hint_ptr->target_downlink_bandwidth_kbps =
-      hint->target_downlink_bandwidth_kbps();
+      hint.target_downlink_bandwidth_kbps();
   hint_ptr->kilobytes_to_buffer_before_throttle =
-      hint->kilobytes_to_buffer_before_throttle();
-  hint_ptr->target_downlink_rtt_latency = hint->target_downlink_rtt_latency();
-  hint_ptr->max_throttling_delay = hint->max_throttling_delay();
+      hint.kilobytes_to_buffer_before_throttle();
+  hint_ptr->target_downlink_rtt_latency = hint.target_downlink_rtt_latency();
+  hint_ptr->max_throttling_delay = hint.max_throttling_delay();
 
   if (render_frame_host->GetRemoteAssociatedInterfaces()) {
     render_frame_host->GetRemoteAssociatedInterfaces()->GetInterface(
diff --git a/chrome/browser/lite_video/lite_video_observer.h b/chrome/browser/lite_video/lite_video_observer.h
index 48d6596..283f3e3 100644
--- a/chrome/browser/lite_video/lite_video_observer.h
+++ b/chrome/browser/lite_video/lite_video_observer.h
@@ -24,6 +24,10 @@
 class LiteVideoHint;
 }  // namespace lite_video
 
+namespace optimization_guide {
+enum class OptimizationGuideDecision;
+}  // namespace optimization_guide
+
 class LiteVideoObserver
     : public content::WebContentsObserver,
       public content::WebContentsUserData<LiteVideoObserver> {
@@ -58,9 +62,16 @@
   // Callback run after a hint and blocklist reason is available for use
   // within the agent associated with |render_frame_host_routing_id|.
   void OnHintAvailable(
-      content::GlobalFrameRoutingId render_frame_host_routing_id,
+      const content::GlobalFrameRoutingId& render_frame_host_routing_id,
       base::Optional<lite_video::LiteVideoHint> hint,
-      lite_video::LiteVideoBlocklistReason blocklist_reason);
+      lite_video::LiteVideoBlocklistReason blocklist_reason,
+      optimization_guide::OptimizationGuideDecision opt_guide_decision);
+
+  // Sends the |hint| to the render frame agent corresponding to the
+  // provided global frame routing id.
+  void SendHintToRenderFrameAgentForID(
+      const content::GlobalFrameRoutingId& routing_id,
+      const lite_video::LiteVideoHint& hint);
 
   // The decider capable of making decisions about whether LiteVideos should be
   // applied and the params to use when throttling media requests.
@@ -76,6 +87,11 @@
   // commits.
   bool is_coinflip_holdback_ = false;
 
+  // The set of routing ids corresponding to render frames that are waiting
+  // for the decision of whether to throttle media requests that
+  // occur within that frame.
+  std::set<content::GlobalFrameRoutingId> routing_ids_to_notify_;
+
   // Used to get a weak pointer to |this|.
   base::WeakPtrFactory<LiteVideoObserver> weak_ptr_factory_{this};
 
diff --git a/chrome/browser/metrics/cros_healthd_metrics_provider.cc b/chrome/browser/metrics/cros_healthd_metrics_provider.cc
index adb05962..80ca54eb 100644
--- a/chrome/browser/metrics/cros_healthd_metrics_provider.cc
+++ b/chrome/browser/metrics/cros_healthd_metrics_provider.cc
@@ -4,11 +4,15 @@
 
 #include "chrome/browser/metrics/cros_healthd_metrics_provider.h"
 
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/logging.h"
 #include "base/strings/string_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
 #include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
@@ -17,41 +21,80 @@
 
 using metrics::SystemProfileProto;
 
+namespace {
+
+constexpr base::TimeDelta kServiceDiscoveryTimeout =
+    base::TimeDelta::FromSeconds(5);
+
+}  // namespace
+
 CrosHealthdMetricsProvider::CrosHealthdMetricsProvider() = default;
 CrosHealthdMetricsProvider::~CrosHealthdMetricsProvider() = default;
 
+base::TimeDelta CrosHealthdMetricsProvider::GetTimeout() {
+  return kServiceDiscoveryTimeout;
+}
+
 void CrosHealthdMetricsProvider::AsyncInit(base::OnceClosure done_callback) {
   const std::vector<chromeos::cros_healthd::mojom::ProbeCategoryEnum>
       categories_to_probe = {chromeos::cros_healthd::mojom::ProbeCategoryEnum::
                                  kNonRemovableBlockDevices};
+  DCHECK(init_callback_.is_null());
+  init_callback_ = std::move(done_callback);
+  initialized_ = false;
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&CrosHealthdMetricsProvider::OnProbeTimeout,
+                     weak_ptr_factory_.GetWeakPtr()),
+      GetTimeout());
   GetService()->ProbeTelemetryInfo(
       categories_to_probe,
       base::BindOnce(&CrosHealthdMetricsProvider::OnProbeDone,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(done_callback)));
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+bool CrosHealthdMetricsProvider::IsInitialized() {
+  return initialized_;
+}
+
+void CrosHealthdMetricsProvider::OnProbeTimeout() {
+  base::ScopedClosureRunner runner(std::move(init_callback_));
+  DVLOG(1) << "cros_healthd: endpoint is not found.";
+
+  // Invalidate OnProbeDone callback.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+
+  devices_.clear();
+  initialized_ = false;
 }
 
 void CrosHealthdMetricsProvider::OnProbeDone(
-    base::OnceClosure done_callback,
     chromeos::cros_healthd::mojom::TelemetryInfoPtr ptr) {
-  base::ScopedClosureRunner runner(std::move(done_callback));
+  base::ScopedClosureRunner runner(std::move(init_callback_));
+
+  // Invalidate OnProbeTimeout callback.
+  weak_ptr_factory_.InvalidateWeakPtrs();
+
   devices_.clear();
+  initialized_ = true;
 
   if (ptr.is_null()) {
-    LOG(ERROR) << "cros_healthd: Empty response";
+    DVLOG(1) << "cros_healthd: Empty response";
     return;
   }
 
   const auto& block_device_result = ptr->block_device_result;
   if (block_device_result.is_null()) {
-    LOG(ERROR) << "cros_healthd: No block device info";
+    DVLOG(1) << "cros_healthd: No block device info";
     return;
   }
 
   auto tag = block_device_result->which();
   if (tag == chromeos::cros_healthd::mojom::NonRemovableBlockDeviceResult::Tag::
                  ERROR) {
-    LOG(ERROR) << "cros_healthd: Error getting block device info: "
-               << block_device_result->get_error()->msg;
+    DVLOG(1) << "cros_healthd: Error getting block device info: "
+             << block_device_result->get_error()->msg;
     return;
   }
   DCHECK_EQ(tag, chromeos::cros_healthd::mojom::NonRemovableBlockDeviceResult::
diff --git a/chrome/browser/metrics/cros_healthd_metrics_provider.h b/chrome/browser/metrics/cros_healthd_metrics_provider.h
index 9429b0e..c3a409b4 100644
--- a/chrome/browser/metrics/cros_healthd_metrics_provider.h
+++ b/chrome/browser/metrics/cros_healthd_metrics_provider.h
@@ -5,7 +5,10 @@
 #ifndef CHROME_BROWSER_METRICS_CROS_HEALTHD_METRICS_PROVIDER_H_
 #define CHROME_BROWSER_METRICS_CROS_HEALTHD_METRICS_PROVIDER_H_
 
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
 #include "components/metrics/metrics_provider.h"
 #include "mojo/public/cpp/bindings/remote.h"
@@ -22,17 +25,25 @@
   void AsyncInit(base::OnceClosure done_callback) override;
   void ProvideSystemProfileMetrics(
       metrics::SystemProfileProto* system_profile_proto) override;
+  bool IsInitialized();
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(CrosHealthdMetricsProviderTest, EndToEndTimeout);
+
   chromeos::cros_healthd::mojom::CrosHealthdProbeService* GetService();
   void OnDisconnect();
-  void OnProbeDone(base::OnceClosure done_callback,
-                   chromeos::cros_healthd::mojom::TelemetryInfoPtr ptr);
+  void OnProbeDone(chromeos::cros_healthd::mojom::TelemetryInfoPtr ptr);
+  void OnProbeTimeout();
+
+  static base::TimeDelta GetTimeout();
 
   mojo::Remote<chromeos::cros_healthd::mojom::CrosHealthdProbeService> service_;
   std::vector<metrics::SystemProfileProto::Hardware::InternalStorageDevice>
       devices_;
 
+  base::OnceClosure init_callback_;
+  bool initialized_ = false;
+
   base::WeakPtrFactory<CrosHealthdMetricsProvider> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/metrics/cros_healthd_metrics_provider_unittest.cc b/chrome/browser/metrics/cros_healthd_metrics_provider_unittest.cc
index 67a19cae..fe704f2 100644
--- a/chrome/browser/metrics/cros_healthd_metrics_provider_unittest.cc
+++ b/chrome/browser/metrics/cros_healthd_metrics_provider_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
+#include "base/time/time.h"
 #include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
 #include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
 #include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
@@ -31,8 +32,8 @@
     base::RunLoop().RunUntilIdle();
   }
 
- private:
-  base::test::TaskEnvironment task_environment_;
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
 };
 
 TEST_F(CrosHealthdMetricsProviderTest, EndToEnd) {
@@ -105,3 +106,20 @@
   }));
   run_loop.Run();
 }
+
+TEST_F(CrosHealthdMetricsProviderTest, EndToEndTimeout) {
+  chromeos::cros_healthd::FakeCrosHealthdClient::Get()->SetCallbackDelay(
+      CrosHealthdMetricsProvider::GetTimeout() +
+      base::TimeDelta::FromSeconds(5));
+
+  base::RunLoop run_loop;
+  CrosHealthdMetricsProvider provider;
+  provider.AsyncInit(base::BindOnce(
+      [](base::OnceClosure callback) { std::move(callback).Run(); },
+      run_loop.QuitClosure()));
+
+  // FastForward by timeout period.
+  task_environment_.FastForwardBy(CrosHealthdMetricsProvider::GetTimeout());
+  run_loop.Run();
+  ASSERT_FALSE(provider.IsInitialized());
+}
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_prefs.cc b/chrome/browser/nearby_sharing/common/nearby_share_prefs.cc
index 98d1f84..71dc325 100644
--- a/chrome/browser/nearby_sharing/common/nearby_share_prefs.cc
+++ b/chrome/browser/nearby_sharing/common/nearby_share_prefs.cc
@@ -34,8 +34,6 @@
     "nearby_sharing.scheduler.contact_upload";
 const char kNearbySharingSchedulerDownloadDeviceDataPrefName[] =
     "nearby_sharing.scheduler.download_device_data";
-const char kNearbySharingSchedulerUploadDeviceNamePrefName[] =
-    "nearby_sharing.scheduler.upload_device_name";
 const char kNearbySharingPublicCertificateExpirationDictPrefName[] =
     "nearbyshare.public_certificate_expiration_dict";
 const char kNearbySharingPrivateCertificateListPrefName[] =
@@ -73,8 +71,6 @@
       prefs::kNearbySharingSchedulerContactUploadPrefName);
   registry->RegisterDictionaryPref(
       prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName);
-  registry->RegisterDictionaryPref(
-      prefs::kNearbySharingSchedulerUploadDeviceNamePrefName);
   registry->RegisterTimePref(
       prefs::kNearbySharingOnboardingDismissedTimePrefName,
       /*default_value=*/base::Time());
diff --git a/chrome/browser/nearby_sharing/common/nearby_share_prefs.h b/chrome/browser/nearby_sharing/common/nearby_share_prefs.h
index 04ce8df..af6af35 100644
--- a/chrome/browser/nearby_sharing/common/nearby_share_prefs.h
+++ b/chrome/browser/nearby_sharing/common/nearby_share_prefs.h
@@ -22,7 +22,6 @@
 extern const char kNearbySharingSchedulerContactDownloadPrefName[];
 extern const char kNearbySharingSchedulerContactUploadPrefName[];
 extern const char kNearbySharingSchedulerDownloadDeviceDataPrefName[];
-extern const char kNearbySharingSchedulerUploadDeviceNamePrefName[];
 extern const char kNearbySharingPublicCertificateExpirationDictPrefName[];
 extern const char kNearbySharingPrivateCertificateListPrefName[];
 extern const char kNearbySharingSchedulerDownloadPublicCertificatesPrefName[];
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc
index 4c91bcb..e5134b72 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.cc
@@ -8,13 +8,11 @@
 #include "chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h"
 
 NearbyShareDeviceDataUpdater::Request::Request(
-    base::Optional<std::string> device_name,
     base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
     base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
         certificates,
     ResultCallback callback)
-    : device_name(std::move(device_name)),
-      contacts(std::move(contacts)),
+    : contacts(std::move(contacts)),
       certificates(std::move(certificates)),
       callback(std::move(callback)) {}
 
@@ -34,13 +32,12 @@
 NearbyShareDeviceDataUpdater::~NearbyShareDeviceDataUpdater() = default;
 
 void NearbyShareDeviceDataUpdater::UpdateDeviceData(
-    base::Optional<std::string> device_name,
     base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
     base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
         certificates,
     ResultCallback callback) {
-  pending_requests_.emplace(std::move(device_name), std::move(contacts),
-                            std::move(certificates), std::move(callback));
+  pending_requests_.emplace(std::move(contacts), std::move(certificates),
+                            std::move(callback));
   ProcessRequestQueue();
 }
 
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h
index 9945ef6..07c8941 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater.h
@@ -18,6 +18,11 @@
 // overriding HandleNextRequest(), which is invoked when the next request is
 // ready to be run. Implementations should call FinishAttempt() with the result
 // of the attempt and possibly the response.
+//
+// NOTE: We do *not* support upload of the device name. This field of the proto
+// appears to be a relic of the old Nearby Share model. Upload of the field
+// could be a privacy concern that we want to avoid.
+//
 // TODO(crbug.com/1105547): Instead of queuing requests, hold a single pending
 // request and update the fields as other UpdateDeviceData() call are made.
 // Then, queue up all of callbacks from the merged requests in the Request
@@ -31,8 +36,7 @@
           response)>;
 
   struct Request {
-    Request(base::Optional<std::string> device_name,
-            base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
+    Request(base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
             base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
                 certificates,
             ResultCallback callback);
@@ -42,7 +46,6 @@
     Request& operator=(const Request&) = delete;
     ~Request();
 
-    base::Optional<std::string> device_name;
     base::Optional<std::vector<nearbyshare::proto::Contact>> contacts;
     base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
         certificates;
@@ -58,8 +61,6 @@
   // Queue up an UpdateDevice RPC request to update the following fields on the
   // Nearby server if the parameter is not base::nullopt:
   //
-  // |device_name|: The device display name, for example, "Joe's Pixel".
-  //
   // |contacts|: The list of contacts that the Nearby server will send
   //             all-contacts-visibility certificates to. Contacts marked
   //             is_selected will be sent selected-contacts-visibility
@@ -71,7 +72,6 @@
   // If only the UpdateDevice RPC response data is desired, set all
   // aforementioned parameters to base::nullopt.
   void UpdateDeviceData(
-      base::Optional<std::string> device_name,
       base::Optional<std::vector<nearbyshare::proto::Contact>> contacts,
       base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>
           certificates,
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc
index b7444f3..eb99440 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl.cc
@@ -11,7 +11,6 @@
 namespace {
 
 const char kDeviceIdPrefix[] = "users/me/devices/";
-const char kDeviceNameFieldMaskPath[] = "device.display_name";
 const char kContactsFieldMaskPath[] = "device.contacts";
 const char kCertificatesFieldMaskPath[] = "device.public_certificates";
 
@@ -63,11 +62,6 @@
 
   nearbyshare::proto::UpdateDeviceRequest request;
   request.mutable_device()->set_name(kDeviceIdPrefix + device_id_);
-  if (pending_requests_.front().device_name) {
-    request.mutable_device()->set_display_name(
-        *pending_requests_.front().device_name);
-    request.mutable_update_mask()->add_paths(kDeviceNameFieldMaskPath);
-  }
   if (pending_requests_.front().contacts) {
     *request.mutable_device()->mutable_contacts() = {
         pending_requests_.front().contacts->begin(),
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
index 71d262fc..258993ad 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_device_data_updater_impl_unittest.cc
@@ -23,7 +23,6 @@
 
 const char kDeviceIdPrefix[] = "users/me/devices/";
 const char kTestDeviceId[] = "test_device_id";
-const char kTestDeviceName[] = "test_device_name";
 const char kTestContactEmail1[] = "test1@gmail.com";
 const char kTestContactEmail2[] = "test2@gmail.com";
 const char kTestCertificateId1[] = "cert_id_1";
@@ -68,7 +67,6 @@
 }
 
 void VerifyRequest(
-    const base::Optional<std::string>& expected_device_name,
     const base::Optional<std::vector<nearbyshare::proto::Contact>>&
         expected_contacts,
     const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
@@ -77,12 +75,10 @@
   std::vector<std::string> field_mask{request.update_mask().paths().begin(),
                                       request.update_mask().paths().end()};
 
-  EXPECT_EQ(static_cast<size_t>(expected_device_name.has_value()) +
-                static_cast<size_t>(expected_contacts.has_value()) +
+  EXPECT_EQ(static_cast<size_t>(expected_contacts.has_value()) +
                 static_cast<size_t>(expected_certificates.has_value()),
             field_mask.size());
-  EXPECT_EQ(expected_device_name.has_value(),
-            base::Contains(field_mask, "device.display_name"));
+
   EXPECT_EQ(expected_contacts.has_value(),
             base::Contains(field_mask, "device.contacts"));
   EXPECT_EQ(expected_certificates.has_value(),
@@ -91,9 +87,6 @@
   EXPECT_EQ(std::string(kDeviceIdPrefix) + kTestDeviceId,
             request.device().name());
 
-  EXPECT_EQ(expected_device_name.value_or(std::string()),
-            request.device().display_name());
-
   if (expected_contacts) {
     ASSERT_EQ(static_cast<int>(expected_contacts->size()),
               request.device().contacts().size());
@@ -145,18 +138,16 @@
   }
 
   void CallUpdateDeviceData(
-      const base::Optional<std::string>& device_name,
       const base::Optional<std::vector<nearbyshare::proto::Contact>>& contacts,
       const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
           certificates) {
     updater_->UpdateDeviceData(
-        device_name, contacts, certificates,
+        contacts, certificates,
         base::BindOnce(&NearbyShareDeviceDataUpdaterImplTest::OnResult,
                        base::Unretained(this)));
   }
 
   void ProcessNextUpdateDeviceDataRequest(
-      const base::Optional<std::string>& expected_device_name,
       const base::Optional<std::vector<nearbyshare::proto::Contact>>&
           expected_contacts,
       const base::Optional<std::vector<nearbyshare::proto::PublicCertificate>>&
@@ -166,8 +157,7 @@
     ASSERT_FALSE(fake_client_factory_.instances().empty());
     FakeNearbyShareClient* client = fake_client_factory_.instances().back();
     ASSERT_EQ(1u, client->update_device_requests().size());
-    VerifyRequest(expected_device_name, expected_contacts,
-                  expected_certificates,
+    VerifyRequest(expected_contacts, expected_certificates,
                   client->update_device_requests()[0].request);
 
     // Send and verify the response.
@@ -214,72 +204,55 @@
 };
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_NoParameters) {
-  CallUpdateDeviceData(/*device_name=*/base::nullopt,
-                       /*contacts=*/base::nullopt,
+  CallUpdateDeviceData(/*contacts=*/base::nullopt,
                        /*certificates=*/base::nullopt);
   ProcessNextUpdateDeviceDataRequest(
-      /*expected_device_name=*/base::nullopt,
       /*expected_contacts=*/base::nullopt,
       /*expected_certificates=*/base::nullopt,
       UpdateDeviceRequestResult::kSuccess);
 }
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_AllParameters) {
-  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
-                       TestCertificateList());
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
-                                     TestCertificateList(),
+  CallUpdateDeviceData(TestContactList(), TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(TestContactList(), TestCertificateList(),
                                      UpdateDeviceRequestResult::kSuccess);
 }
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, Success_OneParameter) {
-  CallUpdateDeviceData(kTestDeviceName,
-                       /*contacts=*/base::nullopt,
+  CallUpdateDeviceData(TestContactList(),
                        /*certificates=*/base::nullopt);
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName,
-                                     /*expected_contacts=*/base::nullopt,
+  ProcessNextUpdateDeviceDataRequest(TestContactList(),
                                      /*expected_certificates=*/base::nullopt,
                                      UpdateDeviceRequestResult::kSuccess);
 }
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, Failure_Timeout) {
-  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
-                       TestCertificateList());
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
-                                     TestCertificateList(),
+  CallUpdateDeviceData(TestContactList(), TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(TestContactList(), TestCertificateList(),
                                      UpdateDeviceRequestResult::kTimeout);
 }
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, Failure_HttpError) {
-  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
-                       TestCertificateList());
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
-                                     TestCertificateList(),
+  CallUpdateDeviceData(TestContactList(), TestCertificateList());
+  ProcessNextUpdateDeviceDataRequest(TestContactList(), TestCertificateList(),
                                      UpdateDeviceRequestResult::kHttpFailure);
 }
 
 TEST_F(NearbyShareDeviceDataUpdaterImplTest, QueuedRequests) {
   // Queue requests while waiting to process.
-  CallUpdateDeviceData(/*device_name=*/base::nullopt,
-                       /*contacts=*/base::nullopt,
+  CallUpdateDeviceData(/*contacts=*/base::nullopt,
                        /*certificates=*/base::nullopt);
-  CallUpdateDeviceData(kTestDeviceName, TestContactList(),
-                       TestCertificateList());
-  CallUpdateDeviceData(kTestDeviceName,
-                       /*contacts=*/base::nullopt,
-                       /*certificates=*/base::nullopt);
+  CallUpdateDeviceData(TestContactList(), TestCertificateList());
+  CallUpdateDeviceData(/*contacts=*/base::nullopt, TestCertificateList());
 
   // Requests are processed in the order they are received.
   ProcessNextUpdateDeviceDataRequest(
-      /*expected_device_name=*/base::nullopt,
       /*expected_contacts=*/base::nullopt,
       /*expected_certificates=*/base::nullopt,
       UpdateDeviceRequestResult::kSuccess);
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName, TestContactList(),
-                                     TestCertificateList(),
+  ProcessNextUpdateDeviceDataRequest(TestContactList(), TestCertificateList(),
                                      UpdateDeviceRequestResult::kTimeout);
-  ProcessNextUpdateDeviceDataRequest(kTestDeviceName,
-                                     /*expected_contacts=*/base::nullopt,
-                                     /*expected_certificates=*/base::nullopt,
+  ProcessNextUpdateDeviceDataRequest(/*expected_contacts=*/base::nullopt,
+                                     TestCertificateList(),
                                      UpdateDeviceRequestResult::kHttpFailure);
 }
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h
index 6b6847f..f1fdcde 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h
@@ -59,9 +59,10 @@
   // not yet been set from an UpdateDevice RPC response.
   virtual base::Optional<std::string> GetIconUrl() const = 0;
 
-  // Uses the UpdateDevice RPC to change the local device name in the Nearby
-  // Share server and in local storage. Must be UTF-8. Observers are notified
-  // via OnLocalDeviceDataChanged() if the device name changes.
+  // Sets and persists the device name in prefs. The device name is *not*
+  // uploaded to the Nearby Share server; the UpdateDevice proto device_name
+  // field in an artifact. Observers are notified via OnLocalDeviceDataChanged()
+  // if the device name changes.
   virtual void SetDeviceName(const std::string& name) = 0;
 
   // Makes an UpdateDevice RPC call to the Nearby Share server to retrieve all
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc
index 70c5927..eb0086e 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.cc
@@ -81,15 +81,6 @@
               pref_service_,
               base::BindRepeating(&NearbyShareLocalDeviceDataManagerImpl::
                                       OnDownloadDeviceDataRequested,
-                                  base::Unretained(this)))),
-      upload_device_name_scheduler_(
-          NearbyShareSchedulerFactory::CreateOnDemandScheduler(
-              /*retry_failures=*/true,
-              /*require_connectivity=*/true,
-              prefs::kNearbySharingSchedulerUploadDeviceNamePrefName,
-              pref_service_,
-              base::BindRepeating(&NearbyShareLocalDeviceDataManagerImpl::
-                                      OnUploadDeviceNameRequested,
                                   base::Unretained(this)))) {}
 
 NearbyShareLocalDeviceDataManagerImpl::
@@ -132,7 +123,6 @@
 
   // TODO(b/161297140): Perform input validation.
   SetStringPref(prefs::kNearbySharingDeviceNamePrefName, name);
-  upload_device_name_scheduler_->MakeImmediateRequest();
 
   NotifyLocalDeviceDataChanged(/*did_device_name_change=*/true,
                                /*did_full_name_change=*/false,
@@ -147,7 +137,7 @@
     std::vector<nearbyshare::proto::Contact> contacts,
     UploadCompleteCallback callback) {
   device_data_updater_->UpdateDeviceData(
-      /*device_name=*/base::nullopt, std::move(contacts),
+      std::move(contacts),
       /*certificates=*/base::nullopt,
       base::BindOnce(
           &NearbyShareLocalDeviceDataManagerImpl::OnUploadContactsFinished,
@@ -158,7 +148,6 @@
     std::vector<nearbyshare::proto::PublicCertificate> certificates,
     UploadCompleteCallback callback) {
   device_data_updater_->UpdateDeviceData(
-      /*device_name=*/base::nullopt,
       /*contacts=*/base::nullopt, std::move(certificates),
       base::BindOnce(
           &NearbyShareLocalDeviceDataManagerImpl::OnUploadCertificatesFinished,
@@ -169,13 +158,10 @@
   // This schedules an immediate download of the full name and icon URL from the
   // server if that has never happened before.
   download_device_data_scheduler_->Start();
-
-  upload_device_name_scheduler_->Start();
 }
 
 void NearbyShareLocalDeviceDataManagerImpl::OnStop() {
   download_device_data_scheduler_->Stop();
-  upload_device_name_scheduler_->Stop();
 }
 
 base::Optional<std::string>
@@ -199,7 +185,6 @@
 
 void NearbyShareLocalDeviceDataManagerImpl::OnDownloadDeviceDataRequested() {
   device_data_updater_->UpdateDeviceData(
-      /*device_name=*/base::nullopt,
       /*contacts=*/base::nullopt,
       /*certificates=*/base::nullopt,
       base::BindOnce(
@@ -207,16 +192,6 @@
           base::Unretained(this)));
 }
 
-void NearbyShareLocalDeviceDataManagerImpl::OnUploadDeviceNameRequested() {
-  device_data_updater_->UpdateDeviceData(
-      GetDeviceName(),
-      /*contacts=*/base::nullopt,
-      /*certificates=*/base::nullopt,
-      base::BindOnce(
-          &NearbyShareLocalDeviceDataManagerImpl::OnUploadDeviceNameFinished,
-          base::Unretained(this)));
-}
-
 void NearbyShareLocalDeviceDataManagerImpl::OnDownloadDeviceDataFinished(
     const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
   if (response)
@@ -226,15 +201,6 @@
       /*success=*/response.has_value());
 }
 
-void NearbyShareLocalDeviceDataManagerImpl::OnUploadDeviceNameFinished(
-    const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
-  if (response)
-    HandleUpdateDeviceResponse(response);
-
-  upload_device_name_scheduler_->HandleResult(
-      /*success=*/response.has_value());
-}
-
 void NearbyShareLocalDeviceDataManagerImpl::OnUploadContactsFinished(
     UploadCompleteCallback callback,
     const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response) {
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h
index ff3a2f5..e320737 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl.h
@@ -72,11 +72,8 @@
                      const base::Optional<std::string>& value);
 
   void OnDownloadDeviceDataRequested();
-  void OnUploadDeviceNameRequested();
   void OnDownloadDeviceDataFinished(
       const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response);
-  void OnUploadDeviceNameFinished(
-      const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response);
   void OnUploadContactsFinished(
       UploadCompleteCallback callback,
       const base::Optional<nearbyshare::proto::UpdateDeviceResponse>& response);
@@ -89,7 +86,6 @@
   PrefService* pref_service_ = nullptr;
   std::unique_ptr<NearbyShareDeviceDataUpdater> device_data_updater_;
   std::unique_ptr<NearbyShareScheduler> download_device_data_scheduler_;
-  std::unique_ptr<NearbyShareScheduler> upload_device_name_scheduler_;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_LOCAL_DEVICE_DATA_NEARBY_SHARE_LOCAL_DEVICE_DATA_MANAGER_IMPL_H_
diff --git a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
index 247659847..52c6b578 100644
--- a/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
+++ b/chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager_impl_unittest.cc
@@ -118,30 +118,6 @@
     manager_.reset();
   }
 
-  void SetDeviceName(
-      const std::string& device_name,
-      const base::Optional<nearbyshare::proto::UpdateDeviceResponse>&
-          response) {
-    manager_->SetDeviceName(device_name);
-    EXPECT_EQ(device_name, manager_->GetDeviceName());
-
-    // The scheduler requests an upload of the device name to the server.
-    EXPECT_TRUE(updater()->pending_requests().empty());
-    device_name_scheduler()->InvokeRequestCallback();
-    EXPECT_FALSE(updater()->pending_requests().empty());
-    EXPECT_EQ(device_name, updater()->pending_requests().front().device_name);
-    EXPECT_FALSE(updater()->pending_requests().front().contacts);
-    EXPECT_FALSE(updater()->pending_requests().front().certificates);
-
-    size_t num_handled_results =
-        device_name_scheduler()->handled_results().size();
-    updater()->RunNextRequest(response);
-    EXPECT_EQ(num_handled_results + 1,
-              device_name_scheduler()->handled_results().size());
-    EXPECT_EQ(response.has_value(),
-              device_name_scheduler()->handled_results().back());
-  }
-
   void DownloadDeviceData(
       const base::Optional<nearbyshare::proto::UpdateDeviceResponse>&
           response) {
@@ -152,7 +128,6 @@
     device_data_scheduler()->InvokeRequestCallback();
     EXPECT_FALSE(updater()->pending_requests().empty());
 
-    EXPECT_FALSE(updater()->pending_requests().front().device_name);
     EXPECT_FALSE(updater()->pending_requests().front().contacts);
     EXPECT_FALSE(updater()->pending_requests().front().certificates);
 
@@ -175,15 +150,16 @@
                           bool success) { *returned_success = success; },
                        &returned_success));
 
-    EXPECT_FALSE(updater()->pending_requests().front().device_name);
     EXPECT_FALSE(updater()->pending_requests().front().certificates);
-    std::vector<nearbyshare::proto::Contact> fake_contacts;
-    for (size_t i = 0; i < fake_contacts.size(); ++i) {
-      EXPECT_EQ(fake_contacts[i].SerializeAsString(), updater()
-                                                          ->pending_requests()
-                                                          .front()
-                                                          .contacts->at(i)
-                                                          .SerializeAsString());
+    std::vector<nearbyshare::proto::Contact> expected_fake_contacts =
+        GetFakeContacts();
+    for (size_t i = 0; i < expected_fake_contacts.size(); ++i) {
+      EXPECT_EQ(expected_fake_contacts[i].SerializeAsString(),
+                updater()
+                    ->pending_requests()
+                    .front()
+                    .contacts->at(i)
+                    .SerializeAsString());
     }
 
     EXPECT_FALSE(returned_success);
@@ -201,11 +177,11 @@
                           bool success) { *returned_success = success; },
                        &returned_success));
 
-    EXPECT_FALSE(updater()->pending_requests().front().device_name);
     EXPECT_FALSE(updater()->pending_requests().front().contacts);
-    std::vector<nearbyshare::proto::PublicCertificate> fake_certificates;
-    for (size_t i = 0; i < fake_certificates.size(); ++i) {
-      EXPECT_EQ(fake_certificates[i].SerializeAsString(),
+    std::vector<nearbyshare::proto::PublicCertificate>
+        expected_fake_certificates = GetFakeCertificates();
+    for (size_t i = 0; i < expected_fake_certificates.size(); ++i) {
+      EXPECT_EQ(expected_fake_certificates[i].SerializeAsString(),
                 updater()
                     ->pending_requests()
                     .front()
@@ -225,11 +201,6 @@
   FakeNearbyShareDeviceDataUpdater* updater() {
     return updater_factory_.instances().back();
   }
-  FakeNearbyShareScheduler* device_name_scheduler() {
-    return scheduler_factory_.pref_name_to_on_demand_instance()
-        .at(prefs::kNearbySharingSchedulerUploadDeviceNamePrefName)
-        .fake_scheduler;
-  }
   FakeNearbyShareScheduler* device_data_scheduler() {
     return scheduler_factory_.pref_name_to_periodic_instance()
         .at(prefs::kNearbySharingSchedulerDownloadDeviceDataPrefName)
@@ -246,16 +217,6 @@
     EXPECT_EQ(manager_->GetId(),
               updater_factory_.instances().back()->device_id());
 
-    // Verify device name scheduler input parameters.
-    FakeNearbyShareSchedulerFactory::OnDemandInstance
-        device_name_scheduler_instance =
-            scheduler_factory_.pref_name_to_on_demand_instance().at(
-                prefs::kNearbySharingSchedulerUploadDeviceNamePrefName);
-    EXPECT_TRUE(device_name_scheduler_instance.fake_scheduler);
-    EXPECT_TRUE(device_name_scheduler_instance.retry_failures);
-    EXPECT_TRUE(device_name_scheduler_instance.require_connectivity);
-    EXPECT_EQ(&pref_service_, device_name_scheduler_instance.pref_service);
-
     // Verify device data scheduler input parameters.
     FakeNearbyShareSchedulerFactory::PeriodicInstance
         device_data_scheduler_instance =
@@ -294,50 +255,18 @@
   EXPECT_EQ(id, manager()->GetId());
 }
 
-TEST_F(NearbyShareLocalDeviceDataManagerImplTest, SetDeviceName_Success) {
+TEST_F(NearbyShareLocalDeviceDataManagerImplTest, SetDeviceName) {
   CreateManager();
-  EXPECT_FALSE(manager()->GetDeviceName());
-  EXPECT_FALSE(manager()->GetFullName());
-  EXPECT_FALSE(manager()->GetIconUrl());
   EXPECT_TRUE(notifications().empty());
-  SetDeviceName(kFakeDeviceName, CreateResponse(kFakeFullName, kFakeIconUrl));
+  manager()->SetDeviceName(kFakeDeviceName);
   EXPECT_EQ(kFakeDeviceName, manager()->GetDeviceName());
-  EXPECT_EQ(kFakeFullName, manager()->GetFullName());
-  EXPECT_EQ(kFakeIconUrl, manager()->GetIconUrl());
-  EXPECT_EQ(2u, notifications().size());
-  EXPECT_EQ(ObserverNotification(/*did_device_name_change=*/true,
-                                 /*did_full_name_change=*/false,
-                                 /*did_icon_url_change=*/false),
-            notifications()[0]);
-  EXPECT_EQ(ObserverNotification(/*did_device_name_change=*/false,
-                                 /*did_full_name_change=*/true,
-                                 /*did_icon_url_change=*/true),
-            notifications()[1]);
-
-  // The data is persisted.
-  DestroyManager();
-  CreateManager();
-  EXPECT_EQ(kFakeDeviceName, manager()->GetDeviceName());
-  EXPECT_EQ(kFakeFullName, manager()->GetFullName());
-  EXPECT_EQ(kFakeIconUrl, manager()->GetIconUrl());
-}
-
-TEST_F(NearbyShareLocalDeviceDataManagerImplTest, SetDeviceName_Failure) {
-  CreateManager();
-  SetDeviceName(kFakeDeviceName, /*response=*/base::nullopt);
-  EXPECT_EQ(kFakeDeviceName, manager()->GetDeviceName());
-
-  // No full name or icon URL set because response was null.
-  EXPECT_EQ(base::nullopt, manager()->GetFullName());
-  EXPECT_EQ(base::nullopt, manager()->GetIconUrl());
-
   EXPECT_EQ(1u, notifications().size());
   EXPECT_EQ(ObserverNotification(/*did_device_name_change=*/true,
                                  /*did_full_name_change=*/false,
                                  /*did_icon_url_change=*/false),
             notifications()[0]);
 
-  // The device name is still persisted even if upload fails.
+  // The data is persisted.
   DestroyManager();
   CreateManager();
   EXPECT_EQ(kFakeDeviceName, manager()->GetDeviceName());
diff --git a/chrome/browser/nearby_sharing/proto/rpc_resources.proto b/chrome/browser/nearby_sharing/proto/rpc_resources.proto
index 1475bbe..da6622fe 100644
--- a/chrome/browser/nearby_sharing/proto/rpc_resources.proto
+++ b/chrome/browser/nearby_sharing/proto/rpc_resources.proto
@@ -112,7 +112,11 @@
   // identity of the requester.
   string name = 1;
 
-  // The device name to show members of this contact. Ex: "Joe's Pixel"
+  // The device name to show members of this contact. Ex: "Joe's Pixel".
+  //
+  // NOTE: Do not use on Chrome. This appears to be an artifact of the old
+  // Nearby Share model, and could be a privacy risk that we want to avoid.
+  // The display name is instead included in the certificate encrypted metadata.
   string display_name = 2;
 
   // Users that this user has added to indicate that they may see this
diff --git a/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc b/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc
index f36778d1..1e1f8a55 100644
--- a/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc
+++ b/chrome/browser/payments/payment_handler_just_in_time_installation_browsertest.cc
@@ -4,9 +4,11 @@
 
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "chrome/test/payments/payment_request_platform_browsertest_base.h"
 #include "components/payments/core/features.h"
 #include "components/payments/core/journey_logger.h"
+#include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -89,6 +91,88 @@
       "\"https://henrypay.com/webpay\" is not supported.\n\n\n\n\n");
 }
 
+using PaymentHandlerSkipSheetTest = PaymentHandlerJustInTimeInstallationTest;
+
+IN_PROC_BROWSER_TEST_F(PaymentHandlerSkipSheetTest, SkipWithUserGesture) {
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSingleEvent(TestEvent::kPaymentCompleted);
+  EXPECT_TRUE(
+      content::ExecJs(GetActiveWebContents(),
+                      "testPaymentMethods([ "
+                      " {supportedMethods: 'https://kylepay.com/webpay'}])"));
+  WaitForObservedEvent();
+  ExpectBodyContains("kylepay.com/webpay");
+
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_AVAILABLE_METHOD_OTHER);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SELECTED_OTHER);
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentHandlerSkipSheetTest, NoSkipWithoutUserGesture) {
+  // When shipping is not requested, kylepay.com cannot leverage skip-the-sheet
+  // for being the only payment app that can fulfill all delegation requests. So
+  // if there is no user gesture, the request should stop at the payment sheet
+  // waiting for user action.
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSingleEvent(TestEvent::kAppListReady);
+  EXPECT_TRUE(
+      content::ExecJs(GetActiveWebContents(),
+                      "testPaymentMethods([ "
+                      " {supportedMethods: 'https://kylepay.com/webpay'}])",
+                      content::EXECUTE_SCRIPT_NO_USER_GESTURE));
+  WaitForObservedEvent();
+  EXPECT_TRUE(content::ExecJs(GetActiveWebContents(), "abort()"));
+
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+
+  // TODO(crbug.com/1122198): EVENT_SHOWN is not always logged on Android.
+#if !defined(OS_ANDROID)
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+#endif
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_AVAILABLE_METHOD_OTHER);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SELECTED_OTHER);
+}
+
+class SecurePaymentConfirmationSkipSheetTest
+    : public PaymentHandlerJustInTimeInstallationTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PaymentHandlerJustInTimeInstallationTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(
+        switches::kEnableExperimentalWebPlatformFeatures);
+  }
+};
+
+// TODO(crbug.com/825270): Remove this special case user gesture exception is
+// removed.
+IN_PROC_BROWSER_TEST_F(SecurePaymentConfirmationSkipSheetTest,
+                       SkipWithoutUserGesture) {
+  base::HistogramTester histogram_tester;
+  ResetEventWaiterForSingleEvent(TestEvent::kPaymentCompleted);
+  EXPECT_TRUE(
+      content::ExecJs(GetActiveWebContents(),
+                      "testPaymentMethods([ "
+                      " {supportedMethods: 'https://kylepay.com/webpay'}])",
+                      content::EXECUTE_SCRIPT_NO_USER_GESTURE));
+  WaitForObservedEvent();
+  ExpectBodyContains("kylepay.com/webpay");
+
+  std::vector<base::Bucket> buckets =
+      histogram_tester.GetAllSamples("PaymentRequest.Events");
+  ASSERT_EQ(1U, buckets.size());
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW);
+  EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SHOWN);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_AVAILABLE_METHOD_OTHER);
+  EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SELECTED_OTHER);
+}
+
 class AlwaysAllowJustInTimePaymentAppTest
     : public PaymentHandlerJustInTimeInstallationTest,
       public testing::WithParamInterface<bool> {
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 9e8f4b0..ec83b79b 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -97,8 +97,6 @@
 #include "ui/accessibility/ax_tree.h"
 #include "ui/accessibility/platform/ax_platform_node_delegate_base.h"
 #include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/clipboard_monitor.h"
-#include "ui/base/clipboard/clipboard_observer.h"
 #include "ui/base/clipboard/test/test_clipboard.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/point.h"
@@ -1898,29 +1896,21 @@
   EXPECT_EQ("page=2&zoom=100,0,200", url.ref());
 }
 
-class PDFExtensionClipboardTest : public PDFExtensionTest,
-                                  public ui::ClipboardObserver {
+class PDFExtensionClipboardTest : public PDFExtensionTest {
  public:
   PDFExtensionClipboardTest() : guest_contents_(nullptr) {}
   ~PDFExtensionClipboardTest() override {}
 
-  // PDFExtensionTest:
   void SetUpOnMainThread() override {
     PDFExtensionTest::SetUpOnMainThread();
     ui::TestClipboard::CreateForCurrentThread();
   }
+
   void TearDownOnMainThread() override {
     ui::Clipboard::DestroyClipboardForCurrentThread();
     PDFExtensionTest::TearDownOnMainThread();
   }
 
-  // ui::ClipboardObserver:
-  void OnClipboardDataChanged() override {
-    DCHECK(!clipboard_changed_);
-    clipboard_changed_ = true;
-    std::move(clipboard_quit_closure_).Run();
-  }
-
   void LoadTestComboBoxPdfGetGuestContents() {
     GURL test_pdf_url(embedded_test_server()->GetURL("/pdf/combobox_form.pdf"));
     guest_contents_ = LoadPdfGetGuestContents(test_pdf_url);
@@ -2017,30 +2007,45 @@
   }
 
  private:
+  // Waits and polls the clipboard of a given |clipboard_buffer| until its
+  // contents reaches the length of |expected|. Then checks and see if the
+  // clipboard contents matches |expected|.
+  // TODO(thestig): Change this to avoid polling after https://crbug.com/755826
+  // has been fixed.
   void CheckClipboard(ui::ClipboardBuffer clipboard_buffer,
                       const std::string& expected) {
-    ui::ClipboardMonitor::GetInstance()->AddObserver(this);
-    DCHECK(!clipboard_changed_);
-    DCHECK(!clipboard_quit_closure_);
-
-    base::RunLoop run_loop;
-    clipboard_quit_closure_ = run_loop.QuitClosure();
-    run_loop.Run();
-
-    EXPECT_TRUE(clipboard_changed_);
-    clipboard_changed_ = false;
-    ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
-
     auto* clipboard = ui::Clipboard::GetForCurrentThread();
     std::string clipboard_data;
-    clipboard->ReadAsciiText(clipboard_buffer, /* data_dst=*/nullptr,
-                             &clipboard_data);
+    const std::string& last_data = last_clipboard_data_[clipboard_buffer];
+    if (last_data.size() == expected.size()) {
+      DCHECK_EQ(last_data, expected);
+      clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
+                               &clipboard_data);
+      EXPECT_EQ(expected, clipboard_data);
+      return;
+    }
+
+    const bool expect_increase = last_data.size() < expected.size();
+    while (true) {
+      clipboard->ReadAsciiText(clipboard_buffer, /* data_dst = */ nullptr,
+                               &clipboard_data);
+      if (expect_increase) {
+        if (clipboard_data.size() >= expected.size())
+          break;
+      } else {
+        if (clipboard_data.size() <= expected.size())
+          break;
+      }
+
+      content::RunAllPendingInMessageLoop();
+    }
     EXPECT_EQ(expected, clipboard_data);
+
+    last_clipboard_data_[clipboard_buffer] = clipboard_data;
   }
 
-  base::RepeatingClosure clipboard_quit_closure_;
+  std::map<ui::ClipboardBuffer, std::string> last_clipboard_data_;
   WebContents* guest_contents_;
-  bool clipboard_changed_ = false;
 };
 
 IN_PROC_BROWSER_TEST_F(PDFExtensionClipboardTest,
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 6f40e48..57dd77f 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1515,6 +1515,12 @@
       std::make_unique<SimplePolicyHandler>(key::kURLAllowlist,
                                             policy_prefs::kUrlWhitelist,
                                             base::Value::Type::LIST)));
+  handlers->AddHandler(std::make_unique<SimpleSchemaValidatingPolicyHandler>(
+      key::kSafeBrowsingExtendedReportingEnabled,
+      prefs::kSafeBrowsingScoutReportingEnabled, chrome_schema,
+      SCHEMA_ALLOW_UNKNOWN,
+      SimpleSchemaValidatingPolicyHandler::RECOMMENDED_ALLOWED,
+      SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED));
 
 #if defined(OS_ANDROID)
   handlers->AddHandler(
@@ -1537,13 +1543,6 @@
       SimpleSchemaValidatingPolicyHandler::RECOMMENDED_ALLOWED,
       SimpleSchemaValidatingPolicyHandler::MANDATORY_PROHIBITED));
 
-  handlers->AddHandler(std::make_unique<SimpleSchemaValidatingPolicyHandler>(
-      key::kSafeBrowsingExtendedReportingEnabled,
-      prefs::kSafeBrowsingScoutReportingEnabled, chrome_schema,
-      SCHEMA_ALLOW_UNKNOWN,
-      SimpleSchemaValidatingPolicyHandler::RECOMMENDED_ALLOWED,
-      SimpleSchemaValidatingPolicyHandler::MANDATORY_ALLOWED));
-
   handlers->AddHandler(std::make_unique<SimpleDeprecatingPolicyHandler>(
       std::make_unique<SimplePolicyHandler>(key::kAutoplayWhitelist,
                                             prefs::kAutoplayWhitelist,
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
index 6dae732..eee4030 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
+++ b/chrome/browser/policy/messaging_layer/storage/storage_queue.cc
@@ -307,24 +307,29 @@
     // The last file will become too large, asynchronously close it and add
     // new.
     last_file->Close();
-    auto insert_result = files_.emplace(
-        next_seq_number_,
-        base::MakeRefCounted<SingleFile>(
-            options_.directory()
-                .Append(options_.file_prefix())
-                .AddExtensionASCII(base::NumberToString(next_seq_number_)),
-            /*size=*/0));
-    if (!insert_result.second) {
-      return Status(
-          error::ALREADY_EXISTS,
-          base::StrCat({"Sequence number already assigned: '",
-                        base::NumberToString(next_seq_number_), "'"}));
-    }
-    last_file = insert_result.first->second;
+    ASSIGN_OR_RETURN(last_file, OpenNewWriteableFile());
   }
   return last_file;
 }
 
+StatusOr<scoped_refptr<StorageQueue::SingleFile>>
+StorageQueue::OpenNewWriteableFile() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(storage_queue_sequence_checker_);
+  auto new_file = base::MakeRefCounted<SingleFile>(
+      options_.directory()
+          .Append(options_.file_prefix())
+          .AddExtensionASCII(base::NumberToString(next_seq_number_)),
+      /*size=*/0);
+  RETURN_IF_ERROR(new_file->Open(/*read_only=*/false));
+  auto insert_result = files_.emplace(next_seq_number_, new_file);
+  if (!insert_result.second) {
+    return Status(error::ALREADY_EXISTS,
+                  base::StrCat({"Sequence number already assigned: '",
+                                base::NumberToString(next_seq_number_), "'"}));
+  }
+  return new_file;
+}
+
 Status StorageQueue::WriteHeaderAndBlock(
     base::span<const uint8_t> data,
     scoped_refptr<StorageQueue::SingleFile> file) {
@@ -676,18 +681,7 @@
     return Status::StatusOK();  // Already empty.
   }
   files_.rbegin()->second->Close();
-  auto insert_result = files_.emplace(
-      next_seq_number_,
-      base::MakeRefCounted<SingleFile>(
-          options_.directory()
-              .Append(options_.file_prefix())
-              .AddExtensionASCII(base::NumberToString(next_seq_number_)),
-          /*size=*/0));
-  if (!insert_result.second) {
-    return Status(error::ALREADY_EXISTS,
-                  base::StrCat({"Sequence number already assigned: '",
-                                base::NumberToString(next_seq_number_), "'"}));
-  }
+  ASSIGN_OR_RETURN(scoped_refptr<SingleFile> last_file, OpenNewWriteableFile());
   return Status::StatusOK();
 }
 
diff --git a/chrome/browser/policy/messaging_layer/storage/storage_queue.h b/chrome/browser/policy/messaging_layer/storage/storage_queue.h
index eb52d8c3..389ed75b 100644
--- a/chrome/browser/policy/messaging_layer/storage/storage_queue.h
+++ b/chrome/browser/policy/messaging_layer/storage/storage_queue.h
@@ -262,6 +262,10 @@
   // file will be created and assigned to be the last one.
   StatusOr<scoped_refptr<SingleFile>> AssignLastFile(size_t size);
 
+  // Helper method for Write() and Read(): creates and opens a new empty
+  // writeable file, adding it to |files_|.
+  StatusOr<scoped_refptr<SingleFile>> OpenNewWriteableFile();
+
   // Helper method for Write(): composes record header and writes it to the
   // file, followed by data.
   Status WriteHeaderAndBlock(base::span<const uint8_t> data,
diff --git a/chrome/browser/reputation/url_elision_policy.cc b/chrome/browser/reputation/url_elision_policy.cc
index dfdc066..27bd149d 100644
--- a/chrome/browser/reputation/url_elision_policy.cc
+++ b/chrome/browser/reputation/url_elision_policy.cc
@@ -18,6 +18,8 @@
 
 const base::FeatureParam<int> kMaximumUnelidedHostnameLength{
     &omnibox::kMaybeElideToRegistrableDomain, "max_unelided_host_length", 25};
+const base::FeatureParam<bool> kEnableKeywordBasedElision{
+    &omnibox::kMaybeElideToRegistrableDomain, "enable_keyword_elision", true};
 
 }  // namespace
 
@@ -42,7 +44,8 @@
   // Hostnames using sensitive keywords (typically, brandnames) are often social
   // engineering, and thus should only show the registrable domain.
   auto eTLD_plus_one = GetETLDPlusOne(host);
-  if (HostnameContainsKeyword(url, eTLD_plus_one, top500_domains::kTopKeywords,
+  if (kEnableKeywordBasedElision.Get() &&
+      HostnameContainsKeyword(url, eTLD_plus_one, top500_domains::kTopKeywords,
                               top500_domains::kNumTopKeywords)) {
     return true;
   }
diff --git a/chrome/browser/reputation/url_elision_policy_unittest.cc b/chrome/browser/reputation/url_elision_policy_unittest.cc
index a8da934..6c5f99e 100644
--- a/chrome/browser/reputation/url_elision_policy_unittest.cc
+++ b/chrome/browser/reputation/url_elision_policy_unittest.cc
@@ -15,14 +15,20 @@
 #include "components/url_formatter/spoof_checks/common_words/common_words_test-inc.cc"
 }
 
+namespace {
+
+// Note: This number is arbitrary; we just need to be able to build
+// hostnames that are reliably shorter/longer than the limit.
+const char* kMaxUnelidedHostLengthParam = "20";
+
+}  // namespace
+
 class UrlElisionPolicyTest : public testing::Test {
  public:
   UrlElisionPolicyTest() {
     scoped_feature_list_.InitWithFeaturesAndParameters(
         {{omnibox::kMaybeElideToRegistrableDomain,
-          // Note: This number is arbitrary; we just need to be able to build
-          // hostnames that are reliably shorter/longer than the limit.
-          {{"max_unelided_host_length", "20"}}}},
+          {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}}}},
         {});
     url_formatter::common_words::SetCommonWordDAFSAForTesting(
         test::kDafsa, sizeof(test::kDafsa));
@@ -98,3 +104,39 @@
   EXPECT_FALSE(
       ShouldElideToRegistrableDomain(GURL("ftp://google.login.com/xyz")));
 }
+
+class UrlElisionKeywordPolicyTest : public UrlElisionPolicyTest,
+                                    public testing::WithParamInterface<bool> {
+ public:
+  UrlElisionKeywordPolicyTest() {
+    if (!GetParam()) {
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{omnibox::kMaybeElideToRegistrableDomain,
+            {{"max_unelided_host_length", kMaxUnelidedHostLengthParam}}}},
+          {});
+    } else {
+      scoped_feature_list_.InitWithFeaturesAndParameters(
+          {{omnibox::kMaybeElideToRegistrableDomain,
+            {{"max_unelided_host_length", kMaxUnelidedHostLengthParam},
+             {"enable_keyword_elision", "false"}}}},
+          {});
+    }
+  }
+
+  ~UrlElisionKeywordPolicyTest() override = default;
+
+  bool IsKeywordElisionEnabled() { return !GetParam(); }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlElisionKeywordPolicyTest);
+};
+
+INSTANTIATE_TEST_SUITE_P(All, UrlElisionKeywordPolicyTest, testing::Bool());
+
+// Verify that keyword elision follows the feature parameter.
+TEST_P(UrlElisionKeywordPolicyTest, ElidesOnKeywords) {
+  EXPECT_EQ(IsKeywordElisionEnabled(),
+            ShouldElideToRegistrableDomain(GURL("http://google-evil.com/xyz")));
+}
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index 367c87b..59c19c3 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -252,6 +252,49 @@
     output_dir = "$root_gen_dir/chrome"
   }
 
+  grit("nearby_shared_resources") {
+    source = "nearby_share/shared/nearby_shared_resources.grd"
+
+    grit_flags = [
+      "-E",
+      "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
+    ]
+
+    deps = [ "//chrome/browser/ui/webui/nearby_share:mojom_js" ]
+
+    defines = chrome_grit_defines
+    outputs = [
+      "grit/nearby_shared_resources.h",
+      "grit/nearby_shared_resources_map.cc",
+      "grit/nearby_shared_resources_map.h",
+      "nearby_shared_resources.pak",
+    ]
+    output_dir = "$root_gen_dir/chrome"
+  }
+
+  grit("nearby_shared_resources_v3") {
+    source = "nearby_share/shared/nearby_shared_resources_v3.grd"
+
+    grit_flags = [
+      "-E",
+      "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
+    ]
+
+    deps = [
+      "//chrome/browser/resources/nearby_share/shared:polymer3_elements",
+      "//chrome/browser/ui/webui/nearby_share:mojom_js",
+    ]
+
+    defines = chrome_grit_defines
+    outputs = [
+      "grit/nearby_shared_resources_v3.h",
+      "grit/nearby_shared_resources_v3_map.cc",
+      "grit/nearby_shared_resources_v3_map.h",
+      "nearby_shared_resources_v3.pak",
+    ]
+    output_dir = "$root_gen_dir/chrome"
+  }
+
   grit("new_tab_page_resources") {
     if (optimize_webui) {
       source = "new_tab_page/new_tab_page_resources_vulcanized.grd"
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
index 4ff0a587..f2c973a 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/background_test.js
@@ -2943,3 +2943,51 @@
             .replay();
       });
 });
+
+TEST_F('ChromeVoxBackgroundTest', 'AlertNoAnnouncement', function() {
+  const mockFeedback = this.createMockFeedback();
+  this.runWithLoadedTree(
+      `
+    <button></button>
+  `,
+      function(root) {
+        ChromeVoxState.addObserver(new class {
+          onCurrentRangeChanged(range) {
+            assertNotReached('Range was changed unexpectedly.');
+          }
+        }());
+        const button = root.find({role: RoleType.BUTTON});
+        const alertEvt =
+            new CustomAutomationEvent(EventType.ALERT, button, '', []);
+        mockFeedback
+            .call(DesktopAutomationHandler.instance.onAlert.bind(
+                DesktopAutomationHandler.instance, alertEvt))
+            .call(() => assertFalse(mockFeedback.utteranceInQueue('Alert')))
+            .replay();
+      });
+});
+
+TEST_F('ChromeVoxBackgroundTest', 'AlertAnnouncement', function() {
+  const mockFeedback = this.createMockFeedback();
+  this.runWithLoadedTree(
+      `
+    <button>hello world</button>
+  `,
+      function(root) {
+        ChromeVoxState.addObserver(new class {
+          onCurrentRangeChanged(range) {
+            assertNotReached('Range was changed unexpectedly.');
+          }
+        }());
+
+        const button = root.find({role: RoleType.BUTTON});
+        const alertEvt =
+            new CustomAutomationEvent(EventType.ALERT, button, '', []);
+        mockFeedback
+            .call(DesktopAutomationHandler.instance.onAlert.bind(
+                DesktopAutomationHandler.instance, alertEvt))
+            .expectSpeech('Alert')
+            .expectSpeech('hello world')
+            .replay();
+      });
+});
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
index 938dd4d..9f27c9b 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/desktop_automation_handler.js
@@ -152,10 +152,14 @@
     const node = evt.target;
     const range = cursors.Range.fromNode(node);
 
-    new Output()
-        .withSpeechCategory(TtsCategory.LIVE)
-        .withSpeechAndBraille(range, null, evt.type)
-        .go();
+    const output = new Output()
+                       .withSpeechCategory(TtsCategory.LIVE)
+                       .withSpeechAndBraille(range, null, evt.type);
+
+    // A workaround for alert nodes that contain no actual content.
+    if (output.toString() != (Msgs.getMsg('role_alert'))) {
+      output.go();
+    }
   }
 
   onBlur(evt) {
diff --git a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
index aaa2e71..9b4a137 100644
--- a/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
+++ b/chrome/browser/resources/chromeos/accessibility/chromevox/background/output.js
@@ -2091,7 +2091,7 @@
    */
   toString() {
     return this.speechBuffer_.reduce(function(prev, cur) {
-      if (prev === null) {
+      if (prev === null || prev == '') {
         return cur.toString();
       }
       prev += ' ' + cur.toString();
diff --git a/chrome/browser/resources/nearby_share/nearby_share_dialog_resources.grd b/chrome/browser/resources/nearby_share/nearby_share_dialog_resources.grd
index 52ef92b7..a0c59fe 100644
--- a/chrome/browser/resources/nearby_share/nearby_share_dialog_resources.grd
+++ b/chrome/browser/resources/nearby_share/nearby_share_dialog_resources.grd
@@ -29,36 +29,6 @@
                file="discovery_manager.js"
                type="BINDATA"/>
 
-      <!-- Shared Polymer 2 pages-->
-      <include name="IDR_NEARBY_CONTACT_VISIBILITY_HTML"
-               file="shared/nearby_contact_visibility.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_CONTACT_VISIBILITY_JS"
-               file="shared/nearby_contact_visibility.js" type="BINDATA"/>
-      <include name="IDR_NEARBY_ONBOARDING_PAGE_HTML"
-               file="shared/nearby_onboarding_page.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_ONBOARDING_PAGE_JS"
-               file="shared/nearby_onboarding_page.js" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_HTML"
-               file="shared/nearby_share_settings.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_JS"
-               file="shared/nearby_share_settings.js" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_HTML"
-               file="shared/nearby_share_settings_behavior.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_JS"
-               file="shared/nearby_share_settings_behavior.js" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARED_ICONS_HTML"
-               file="shared/nearby_shared_icons.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_VISIBILITY_PAGE_HTML"
-               file="shared/nearby_visibility_page.html" type="BINDATA"/>
-      <include name="IDR_NEARBY_VISIBILITY_PAGE_JS"
-               file="shared/nearby_visibility_page.js" type="BINDATA"/>
-
-      <!-- Shared images -->
-      <include name="IDR_NEARBY_SHARE_ONBOARDING_SPLASH_SVG"
-               file="shared/nearby_onboarding_splash.svg" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_DEVICE_VISIBILITY_SVG"
-               file="shared/nearby_device_visibility.svg" type="BINDATA"/>
-
       <!-- Generated Polymer 3 elements -->
       <include name="IDR_NEARBY_SHARE_APP_JS"
                file="${root_gen_dir}/chrome/browser/resources/nearby_share/app.js"
@@ -84,26 +54,6 @@
       <include name="IDR_NEARBY_SHARE_NEARBY_PROGRESS_JS"
                file="${root_gen_dir}/chrome/browser/resources/nearby_share/nearby_progress.js"
                use_base_dir="false" type="BINDATA"/>
-
-      <!-- Generated Polymer 2 to 3 elements -->
-      <include name="IDR_NEARBY_CONTACT_VISIBILITY_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.m.js"
-               use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_NEARBY_ONBOARDING_PAGE_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.m.js"
-               use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_share_settings.m.js"
-               use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.m.js"
-               use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_NEARBY_SHARED_ICONS_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.m.js"
-               use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_NEARBY_VISIBILITY_PAGE_M_JS"
-               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.m.js"
-               use_base_dir="false" type="BINDATA"/>
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/resources/nearby_share/shared/BUILD.gn b/chrome/browser/resources/nearby_share/shared/BUILD.gn
index 64d7acd..327d615 100644
--- a/chrome/browser/resources/nearby_share/shared/BUILD.gn
+++ b/chrome/browser/resources/nearby_share/shared/BUILD.gn
@@ -5,6 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/polymer.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
+import("./nearby_shared.gni")
 
 js_type_check("closure_compile") {
   deps = [
@@ -24,6 +25,7 @@
 js_library("nearby_contact_visibility") {
   deps = [
     ":nearby_share_settings_behavior",
+    "//third_party/polymer/v1_0/components-chromium/iron-icon:iron-icon-extracted",
     "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted",
     "//ui/webui/resources/cr_elements/cr_radio_button:cr_card_radio_button",
     "//ui/webui/resources/cr_elements/cr_radio_group:cr_radio_group",
@@ -34,6 +36,7 @@
 js_library("nearby_onboarding_page") {
   deps = [
     ":nearby_share_settings_behavior",
+    "//third_party/polymer/v1_0/components-chromium/iron-icon:iron-icon-extracted",
     "//ui/webui/resources/cr_elements/cr_link_row",
   ]
 }
@@ -138,15 +141,6 @@
   extra_deps = [ ":nearby_visibility_page_module" ]
 }
 
-nearby_shared_auto_imports = [ "chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.html|NearbyShareSettingsBehavior,NearbySettings" ]
-nearby_shared_namespace_rewrites = [
-  "nearby_share.NearbySettings|NearbySettings",
-  "nearby_share.NearbyShareSettingsBehavior|NearbyShareSettingsBehavior",
-  "nearby_share.getNearbyShareSettings|getNearbyShareSettings",
-  "nearby_share.observeNearbyShareSettings|observeNearbyShareSettings",
-  "nearby_share.setNearbyShareSettingsForTesting|setNearbyShareSettingsForTesting",
-]
-
 polymer_modulizer("nearby_contact_visibility") {
   js_file = "nearby_contact_visibility.js"
   html_file = "nearby_contact_visibility.html"
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html
index 0dfe440..17aa6ec 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html
+++ b/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="nearby_share_settings_behavior.html">
 <link rel="import" href="nearby_shared_icons.html">
@@ -61,6 +62,7 @@
         color: var(--google-blue-600);
       }
       .card-icon {
+        fill: var(--google-blue-600);
         margin-block-end: 8px;
       }
 
@@ -77,6 +79,11 @@
         text-align: end;
       }
 
+      #zeroStateImage {
+        height: 200px;
+        width: 200px;
+      }
+
       #zeroStateTextContainer {
         display: flex;
         flex-basis: 50%;
@@ -197,8 +204,9 @@
       <template is="dom-if" if="[[!isVisibilitySelected_(selectedVisibility)]]">
         <div id="zeroStateContainer">
           <div id="zeroStateImageContainer">
-            <img id="zeroStateImage" width="200" height="200"
-                src="/shared/nearby_device_visibility.svg">
+            <iron-icon id="zeroStateImage"
+                icon="nearby-images:nearby-device-visibility">
+            </iron-icon>
           </div>
           <div id="zeroStateTextContainer">
             <div id="zeroStateText" class="cr-title-text">
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_device_visibility.svg b/chrome/browser/resources/nearby_share/shared/nearby_device_visibility.svg
deleted file mode 100644
index 5932080..0000000
--- a/chrome/browser/resources/nearby_share/shared/nearby_device_visibility.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M0 0h200v200H0z"/><path d="M150.441 100.728c0 26.949-21.772 48.794-48.63 48.794-26.858 0-48.63-21.845-48.63-48.794 0-26.95 21.772-48.795 48.63-48.795 26.858 0 48.63 21.845 48.63 48.795" fill="#D2E3FC"/><path d="M176.711 53.44l-12.39-3.317a1.021 1.021 0 0 1-.722-1.25l3.32-12.383a1.022 1.022 0 0 1 1.252-.722l12.39 3.317c.544.146.868.707.722 1.251l-3.32 12.383a1.022 1.022 0 0 1-1.252.722" fill="#34A853"/><path d="M31.832 148.371l-9.514 5.538c-3.553 2.068-4.77 6.644-2.72 10.223 2.053 3.584 6.603 4.813 10.161 2.742l9.514-5.538c3.48-2.026 4.718-6.454 2.844-9.998l-.124-.225c-2.053-3.584-6.603-4.813-10.161-2.742zm8.425 3.736c1.505 2.627.612 5.986-1.99 7.5l-9.514 5.539c-2.597 1.511-5.918.614-7.42-2.008-1.504-2.627-.61-5.986 1.991-7.5l9.514-5.539c2.529-1.471 5.743-.66 7.297 1.804l.122.204z" fill="#EA4335" fill-rule="nonzero"/><path d="M26.693 54.6l-5.899-5.896a2.743 2.743 0 0 1-.711-2.653l2.159-8.054a2.745 2.745 0 0 1 1.943-1.941l8.058-2.158a2.75 2.75 0 0 1 2.655.71l5.9 5.896c.693.694.965 1.705.71 2.653L39.35 51.21a2.746 2.746 0 0 1-1.943 1.942l-8.058 2.158a2.751 2.751 0 0 1-2.655-.71" fill="#FBBC05"/><path d="M26.536 141.312l-5.553-4.145a.552.552 0 0 1-.113-.773l4.149-5.55a.552.552 0 0 1 .773-.112l5.554 4.145a.552.552 0 0 1 .112.773l-4.149 5.55a.552.552 0 0 1-.773.112" fill="#F882FF"/><path d="M102.004 29.332c-39.453 0-71.437 31.965-71.437 71.396 0 39.43 31.984 71.395 71.437 71.395 39.453 0 71.437-31.965 71.437-71.395 0-39.431-31.983-71.396-71.437-71.396zm0 2c38.35 0 69.437 31.07 69.437 69.396s-31.088 69.395-69.437 69.395-69.437-31.07-69.437-69.395c0-38.326 31.088-69.396 69.437-69.396z" fill="#4285F4" fill-rule="nonzero"/><path d="M104.18 73.085a8.864 8.864 0 0 0-4.738 0l-19.099 7.12c-1.232.342-2.075 1.387-2.075 2.572v14.13c0 11.668 5.686 22.805 15.688 29.978 3.332 2.39 6.297 3.737 7.855 3.737 1.558 0 4.523-1.348 7.855-3.737 10.003-7.173 15.688-18.31 15.688-29.977V82.777c0-1.185-.842-2.23-2.075-2.573l-19.099-7.12z" fill="#4285F4"/><path d="M101.768 94.59c-3.19 0-5.789 2.668-5.789 5.945 0 3.276 2.599 5.945 5.79 5.945 3.19 0 5.789-2.669 5.789-5.945 0-3.277-2.6-5.945-5.79-5.945zm-.193 9.115c-1.81 0-3.28-1.51-3.28-3.368 0-1.86 1.47-3.37 3.28-3.37 1.81 0 3.281 1.51 3.281 3.37 0 1.859-1.47 3.368-3.28 3.368zm.193-12.682c-6.14 0-11.384 3.944-13.508 9.512 2.124 5.567 7.368 9.512 13.508 9.512 6.14 0 11.384-3.945 13.509-9.512-2.125-5.568-7.368-9.512-13.509-9.512zm-.193 16.646c-4.726 0-8.942-2.763-11-7.134 2.058-4.371 6.274-7.134 11-7.134 4.727 0 8.942 2.763 11 7.134-2.058 4.37-6.273 7.134-11 7.134z" fill="#FFF" fill-rule="nonzero"/></g></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.html b/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.html
index afcd40f..13367d318 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.html
+++ b/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.html
@@ -2,6 +2,7 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="./nearby_share_settings_behavior.html">
 
 <dom-module id="nearby-onboarding-page">
@@ -42,7 +43,9 @@
       }
 
       #splash-image-column {
+        height: 200px;
         margin: 10px;
+        width: 200px;
       }
 
       #device-name-column {
@@ -81,8 +84,9 @@
       </div>
 
       <div id=center-content>
-        <img id="splash-image-column" width="200" height="200"
-             src="/shared/nearby_onboarding_splash.svg">
+        <iron-icon id="splash-image-column"
+            icon="nearby-images:nearby-onboarding-splash">
+        </iron-icon>
         <div id="device-name-column">
             <div id="device-name-desc-group">
               <div>Device Name</div>
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_splash.svg b/chrome/browser/resources/nearby_share/shared/nearby_onboarding_splash.svg
deleted file mode 100644
index 3d8679ed..0000000
--- a/chrome/browser/resources/nearby_share/shared/nearby_onboarding_splash.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="a" d="M.008.144h30.71v26.652H.007z"/><path d="M3.798.549A5.982 5.982 0 0 0 .812 8.458l5.764 12.741a5.97 5.97 0 0 0 7.9 2.99 5.982 5.982 0 0 0 2.987-7.909L11.697 3.54A5.96 5.96 0 0 0 3.798.55" id="c"/><path d="M1.258 10.212c-1.955 7.205 1.886 14.751 8.58 16.855l.196.063c6.694 2.104 13.705-2.03 15.66-9.234C27.65 10.691 23.81 3.145 17.117 1.04L16.92.978a11.78 11.78 0 0 0-3.546-.549C7.907.43 2.868 4.28 1.258 10.212z" id="e"/><path id="g" d="M0 .13h36.463v36.73H0z"/><path d="M25.094.245L.89 9.568c-.687.265-1.037 1.056-.782 1.769l8.985 25.114c.255.712 1.018 1.075 1.704.811L35 27.939c.687-.265 1.037-1.056.782-1.769L26.798 1.056A1.329 1.329 0 0 0 25.555.16c-.153 0-.31.028-.461.086" id="i"/></defs><g fill="none" fill-rule="evenodd"><path d="M0 0h200v200H0z"/><path d="M110.893 164.142l-6.065 12.062c1.606.235 2.96.506 4.06.814 4.544 1.27 10.262 2.852 15.561 5.64 7.226 3.802 10.566 4.087 10.02.856-3.964-3.923-4.913-5.674-2.848-5.254 2.065.42 5.403 1.107 10.015 2.062.624-.243.804-.791.539-1.644-.208-.67-3.266-2.054-4.064-3.237-.146-.216.396-.215 1.624.003 2.632.41 4.12.547 4.465.41 1.163-.466-.097-2.017-.003-2.827.054-.468.801-.549 1.216-.806.288-.179.267-.554.36-.741.42-.842-3.068-1.44-2.8-2.494.274-1.075 4.274-2.606 1.607-3.406-5.282-1.583-10.813.808-16.629.56-3.877-.166-9.563-.832-17.058-1.998z" fill="#D2E3FC"/><path d="M141.354 171.58l.57.095 1.311.246c1.522.274 1.905.19 2.129-.434.02-.056-.109-.25-.638-.581-.664-.415-1.721-.839-3.074-1.237a.805.805 0 1 1 .454-1.543l.57.174c3.14.992 4.78 2.126 4.204 3.732-.561 1.563-1.636 1.851-3.696 1.512l-1.341-.249c-.275-.05-.504-.09-.735-.126a12.992 12.992 0 0 0-2.067-.174 32.862 32.862 0 0 0-4.908.396.806.806 0 0 1-.92-.672.803.803 0 0 1 .673-.918 34.47 34.47 0 0 1 5.148-.414c.753-.002 1.497.064 2.32.193z" fill="#4682F4" fill-rule="nonzero"/><path d="M134.892 176.05a.803.803 0 1 1 .003-1.609l1.163.008c.546.006.966.015 1.232.028l.092.005a18.507 18.507 0 0 1 2.379.322l.654.138c.519.115 1.48.336 1.707.384l.395.079c1.162.217 1.48.119 1.591-.306.206-.791-.878-1.532-3.807-2.045a.804.804 0 1 1 .276-1.585c3.753.658 5.634 1.944 5.09 4.037-.428 1.64-1.63 1.868-3.876 1.394l-1.942-.436a18.28 18.28 0 0 0-2.16-.345l-.401-.031-.424-.016a88.28 88.28 0 0 0-1.972-.022z" fill="#4682F4" fill-rule="nonzero"/><path d="M141.644 179.567c.18-.31.013-.618-.823-1.159-1.14-.736-3.19-1.51-6.125-2.293a.806.806 0 0 1-.571-.986.803.803 0 0 1 .984-.57c3.084.825 5.27 1.649 6.583 2.498 1.565 1.01 2.102 2.273 1.225 3.504-.514.722-1.262.731-2.752.368l-.552-.143c-.57-.153-1.557-.428-1.585-.435a32.331 32.331 0 0 0-2.211-.532 19.356 19.356 0 0 0-1.642-.258c-1.193-.132-2.08-.185-2.641-.16l-.234.016-.035.06a.798.798 0 0 1-.223.222l-.095.054a.805.805 0 0 1-1.075-.374c-.503-1.04.296-1.495 1.408-1.576.672-.05 1.687.005 3.07.158.58.065 1.169.158 1.778.28.61.12 1.21.262 1.896.443l2.295.625c.494.126.85.198 1.108.22l.186.012c.018.002.028.006.031.013v.013zm-13.848-1.352a.806.806 0 0 1-1.006-.534c-.452-1.475-.264-2.833.571-3.995.9-1.253 2.656-2.153 5.813-3.27l3.54-1.22.187-.068c.695-.257 1.397-.438 2.698-.713l1.718-.36c1.35-.292 2.061-.494 2.677-.773.748-.34.941-.604.836-.965-.172-.587-3.21-.75-7.838-.247l-.935.106c-.32.038-.647.079-.985.122l-5.142.7c-.596.077-1.065.135-1.254.15-2.193.181-7.982-.704-17.529-2.658a.804.804 0 1 1 .323-1.576l2.02.409c8.168 1.631 13.228 2.373 15.054 2.223l.305-.033c1.269-.15 5.264-.712 5.497-.742l1.029-.132c.332-.04.656-.08.973-.116l1.221-.13c5.403-.544 8.286-.313 8.807 1.474.376 1.29-.324 2.248-1.715 2.88l-.285.122c-.624.255-1.323.45-2.45.7l-2.466.52c-.771.17-1.286.304-1.735.454l-1.52.534c-1.005.347-2.173.743-2.13.728-3.045 1.058-4.745 1.9-5.405 2.818-.533.743-.649 1.579-.34 2.588a.804.804 0 0 1-.534 1.004z" fill="#4682F4" fill-rule="nonzero"/><path d="M135.161 182.503c.791 1.153.728 2.38-.312 3.488-1.426 1.52-4.087.752-10.188-2.074l-3.96-1.853a66.2 66.2 0 0 0-2.227-.987c-3.772-1.591-8.276-2.854-13.51-3.787a.806.806 0 0 1-.652-.933.803.803 0 0 1 .932-.652c5.064.903 9.474 2.113 13.233 3.632l.62.257c.83.349 1.486.641 2.657 1.185l3.215 1.507 1.046.481c4.608 2.09 7.048 2.774 7.66 2.122.511-.545.531-.935.16-1.477-.356-.519-.985-1.053-2.102-1.825l-.786-.532c-1.524-1.024-2.835-2.028-3.934-3.013a.805.805 0 1 1 1.072-1.198 33.243 33.243 0 0 0 3.277 2.548l1.027.695c1.343.913 2.13 1.548 2.662 2.262l.11.154z" fill="#4682F4" fill-rule="nonzero"/><path d="M92.163 196.078c.982.182 2.643.273 3.633.406.83.112 1.619-.175 2.423-.405.803-.232.747-.847.919-1.664.695-.113 1.406-.232 2.02-.574.616-.342 1.125-.96 1.137-1.661.007-.395-.558-.19-.444-.568.073-.236.66-1.04.785-1.255.527-.906.161-2.213-.76-2.716.363-.226.476-.726.358-1.135-.118-.409-.42-.74-.742-1.018-2.532-2.183-6.36-1.812-9.443-3.116.583-.446 1.347-.564 2.022-.851.675-.287 1.338-.898 1.241-1.624-.073-.554-.585-.969-1.125-1.117-.542-.148-1.115-.088-1.674-.049-3.745.265-7.532-.417-11.249.108-.252.037-.515.083-.717.238-.27.21-3.883-1.106-3.963-.774-.482 1.974-7.031-4.966-7.839-4.154-.807.812-11.512 9.186-11.706 10.15-.164.811 14.052 7.893 15.264 8.424 2.096.917 12.76 2.606 14.612 2.948 1.548.287 3.7.12 5.248.407z" fill="#D2E3FC"/><path d="M87.628 192.91a.806.806 0 0 1 .445-1.548c4.335 1.25 7.827 1.874 10.84 1.8.923-.021 1.458-.12 1.76-.356.22-.172.26-.694.048-.846a.806.806 0 0 1-.184-1.124.803.803 0 0 1 1.122-.185c1.153.829 1.014 2.634.003 3.425-.67.523-1.447.667-2.71.697-3.209.078-6.845-.572-11.324-1.863zm-.619-10.486a.806.806 0 0 1 .433-1.551l.341.091c1.706.442 6.23 1.446 7.773 1.731.713.132 1.388.288 2.361.538l.836.219c1.116.292 1.938.623 2.638 1.14.524.388.923.874 1.114 1.442.183.543.153 1.141-.125 1.632-.527.932-1.542 1.258-2.914 1.245a10.974 10.974 0 0 1-1.039-.064l-1.324-.156c-.403-.053-.82-.12-1.435-.226l-1.496-.259-1.511-.258a35.12 35.12 0 0 1-3.64-.82.806.806 0 0 1 .433-1.552c1.282.359 2.228.567 3.841.848l3.05.523c.51.085.867.137 1.248.183l.719.084c.47.055.826.083 1.169.086.843.008 1.344-.153 1.5-.428.038-.067.044-.192 0-.324-.074-.22-.266-.454-.545-.66-.445-.328-1.011-.573-1.789-.795l-.8-.214-.913-.233c-.55-.136-1-.238-1.446-.324l-.639-.122c-2.01-.396-6.554-1.415-7.84-1.776z" fill="#4285F4" fill-rule="nonzero"/><path d="M88.364 189.969a.806.806 0 0 1 .423-1.554c2.262.617 6.487 1.543 8.684 1.896 1.54.248 2.447.295 3.257.092.322-.081.51-.183.722-.395.12-.119.2-.406.171-.674-.037-.348-.215-.568-.462-.665l-.096-.03a.806.806 0 0 1 .39-1.563c.924.232 1.649.99 1.767 2.084.078.723-.14 1.497-.636 1.99-.425.423-.87.666-1.466.815-1.087.273-2.155.217-3.902-.064-2.255-.362-6.536-1.3-8.852-1.932zm-20.049-15.742a.806.806 0 0 1-.207-1.12.803.803 0 0 1 1.118-.207l.719.491c5.425 3.677 8.916 5.295 10.089 4.886 1.98-.69 3.677-.83 6.624-.68l4.398.28.608.03.294-.001.671-.012c.994-.007 1.669.11 2.315.521.71.453 1.16 1.257 1.056 2.078-.074.587-.414 1.102-.902 1.477-.446.344-1.076.6-1.943.84l-.503.13c-.52.126-1.46.338-1.569.365a.805.805 0 0 1-.394-1.562l1.556-.361.211-.052c.82-.212 1.391-.428 1.662-.637.172-.132.272-.284.287-.401.02-.154-.107-.38-.325-.518-.287-.183-.648-.259-1.235-.268l-.204-.001-.804.013c-.117 0-.213 0-.312-.004l-1.364-.076-2.767-.185c-3.14-.198-4.788-.125-6.595.465l-.237.08c-1.954.681-5.89-1.188-12.247-5.571zm-11.4 11.051a.806.806 0 0 1 .89-1.342c5.989 3.979 11.392 6.766 16.202 8.364l.532.172c3.514 1.113 6.104 1.57 11.318 2.09l4.4.419c1.719.173 2.897.325 4.1.538l.242.044c1.209.22 1.785.266 2.39.132.619-.137 1.118-.537 1.264-.985l.028-.113a.804.804 0 1 1 1.581.295c-.221 1.193-1.273 2.098-2.527 2.376-.756.167-1.398.149-2.457-.022l-1.265-.22c-1.168-.191-2.397-.337-4.238-.513l-2.742-.256c-5.96-.571-8.723-1.028-12.579-2.25-5.1-1.614-10.81-4.525-17.139-8.73z" fill="#4285F4" fill-rule="nonzero"/><g fill-rule="nonzero"><path d="M78.868 136.46l-.531.008c-.323.008-.621.021-.894.039l-.49.038-.12.016-9.915.101-.382-.018c-3.068-.115-6.78.197-10.366 1.302-2.21.682-4.172 1.626-5.815 2.868-3.822 2.89-5.187 7.466-6.244 17.638-.966 9.309 1.07 16.723 5.068 22.384a24.107 24.107 0 0 0 3.667 4.132c.76.675 1.36 1.117 1.72 1.34.266.167.602.16.861-.005l.093-.07 14.23-12.368c.335-.292.37-.8.078-1.135a.806.806 0 0 0-1.049-.144l-.087.066-13.753 11.953-.117-.088c-.21-.16-.432-.341-.667-.542l-.24-.209a22.505 22.505 0 0 1-3.42-3.857c-3.777-5.348-5.707-12.376-4.781-21.291l.161-1.49c.988-8.676 2.303-12.65 5.453-15.032 1.481-1.12 3.276-1.983 5.318-2.613 3.194-.985 6.534-1.306 9.34-1.247l.704.024.18.009 10.07-.106.264-.026.102-.008c.311-.025.67-.044 1.071-.054a25.64 25.64 0 0 1 3.7.18c3.7.447 7.071 1.653 9.76 3.825 1.895 1.531 3.246 3.777 4.756 7.685l.373.991c.454 1.273 3.058 8.852 4.112 11.6a.805.805 0 0 0 .544.49l.109.02 8.336 1.035-7.493 14.353-.253-.054c-2.408-.554-5.444-2.118-9.083-4.702l-.422-.302c-4.065-2.937-5.343-7.106-3.845-12.686a.806.806 0 0 0-1.556-.416c-1.663 6.198-.174 11.06 4.457 14.405 4.444 3.21 8.108 5.03 11.03 5.445a.81.81 0 0 0 .77-.329l.058-.096 8.3-15.901a.804.804 0 0 0-.513-1.15l-.101-.02-9.004-1.117-.494-1.347a368.1 368.1 0 0 1-.94-2.636l-2.547-7.277c-1.739-4.697-3.268-7.372-5.58-9.24-2.953-2.386-6.604-3.692-10.58-4.173a27.422 27.422 0 0 0-3.403-.198z" fill="#4285F4"/><path d="M61.551 153.314l-.1.002a.805.805 0 0 0-.742.764l.002.1 1.185 15.019a.802.802 0 0 0 .285.552l.087.064 6.522 4.123a.803.803 0 1 0 .95-1.294l-.088-.065-6.18-3.908-1.156-14.617a.805.805 0 0 0-.657-.728l-.108-.012z" fill="#4682F4"/><path d="M63.276 165.48a.805.805 0 0 0-.101 1.601l.101.007h22.233a.805.805 0 0 0 .101-1.602l-.1-.006H63.275z" fill="#4682F4"/></g><path d="M69.765 131.356h5.865l1.533 6.908c-.569 1.266-2.293 2.186-4.332 2.186-2.094 0-3.855-.97-4.376-2.287l1.31-6.807z" fill="#CFE3FF"/><path d="M75.63 130.552h-5.865a.805.805 0 0 0-.791.652l-1.31 6.807a.803.803 0 0 0 .042.447c.666 1.684 2.762 2.796 5.125 2.796 2.296 0 4.343-1.05 5.067-2.661a.803.803 0 0 0 .051-.503l-1.533-6.908a.805.805 0 0 0-.786-.63zm-.647 1.608l1.329 5.987-.027.046c-.557.839-1.897 1.453-3.454 1.453l-.228-.004c-1.506-.058-2.771-.69-3.272-1.52l-.036-.065 1.135-5.897h4.553z" fill="#4285F4" fill-rule="nonzero"/><path d="M76.445 122.877a6.147 6.147 0 0 1 .694 8.688 6.202 6.202 0 0 1-8.72.692 6.147 6.147 0 0 1-.694-8.689 6.202 6.202 0 0 1 8.72-.69z" fill="#CFE3FF"/><path d="M67.112 123.046a6.95 6.95 0 0 0 .785 9.823 7.008 7.008 0 0 0 9.855-.781 6.95 6.95 0 0 0-.785-9.823 7.008 7.008 0 0 0-9.855.781zm8.811.444a5.344 5.344 0 0 1 .604 7.553 5.396 5.396 0 0 1-7.587.601 5.344 5.344 0 0 1-.603-7.553 5.396 5.396 0 0 1 7.586-.601z" fill="#4285F4" fill-rule="nonzero"/><path fill="#4285F4" d="M66.246 124.853h11.057l-.299-2.25-4.155-1.117-2.297.041-2.571 1.65z"/><path d="M81.62 121.472c-.335.523-.8 1.009-1.21 1.469l-1.697 1.912h-6.757l2.306-2.545c1.127-1.244 1.971-2.238 3.384-3.065 1.483-.869 3.377-1.116 4.163.034l.024.037c.355.55.274 1.401-.212 2.158" fill="#0F3EC1"/><path d="M69.625 127.974c.4-.082.79.147.921.52l.03.106c.083.405.424.766.824.886l.121.03a.804.804 0 1 1-.275 1.584 2.827 2.827 0 0 1-2.249-2.178.804.804 0 0 1 .628-.948z" fill="#4285F4" fill-rule="nonzero"/><g transform="translate(87.766 169.167)"><path d="M0 12.79L2.687 1.536A2 2 0 0 1 4.632 0h11.823a2 2 0 0 1 1.928 2.533l-3.88 14.02L0 12.79z" fill="#4682F4"/><ellipse fill="#FFF" cx="6.285" cy="2.818" rx="1.007" ry="1.001"/></g><path d="M89.666 149.902c.488.11.795.595.685 1.082l-.412 1.874a39.22 39.22 0 0 0-.172.87 23.414 23.414 0 0 0-.372 2.834c-.129 2.02-.374 3.896-.757 5.674-.484 2.245-1.087 3.591-2.423 4.63a.907.907 0 0 1-1.271-.159.904.904 0 0 1 .158-1.27c.909-.706 1.363-1.72 1.764-3.582.318-1.475.537-3.028.67-4.69l.05-.72c.053-.81.153-1.625.303-2.51l.154-.84c.123-.641.252-1.23.54-2.509a.906.906 0 0 1 .97-.702l.113.018zM159.996 35.664h-5.559a.805.805 0 0 0-.737.48l-1.71 3.862a.804.804 0 0 0 .734 1.13l9.034.036a.804.804 0 0 0 .737-1.135l-1.765-3.9a.805.805 0 0 0-.734-.473zm-.522 1.608l1.036 2.286-6.55-.027 1.001-2.26h4.513z" fill="#4285F4" fill-rule="nonzero"/><path d="M161.948 41.21l-.376-.071-1.578.03c-2.899.047-5.226.04-6.982-.021l-.323-.012c-12.927-.517-20.131 5.42-29.147 22.158a.804.804 0 0 1-.397.36l-.105.036-19.632 5.21 5.93 13.082.087.008c7.582.697 14.44-1.076 20.608-5.325l.439-.308c6.424-4.572 10.44-10.685 12.07-18.37a.805.805 0 0 1 1.576.333c-1.714 8.08-5.959 14.541-12.71 19.347-6.75 4.804-14.327 6.763-22.696 5.868a.806.806 0 0 1-.599-.374l-.05-.094-6.515-14.37a.803.803 0 0 1 .427-1.074l.1-.034 20.214-5.364.112-.206c8.97-16.498 16.507-22.78 29.546-22.514l1.744.054c1.767.045 4.052.043 6.855-.007l1.075-.021.147.01.31.056.39.08c.139.028.286.06.443.096.888.203 1.871.466 2.924.799 3.008.95 5.976 2.264 8.694 4.002 7.825 5.004 12.045 12.458 10.865 22.73-1.18 10.273-7.632 17.093-17.468 21.09-3.416 1.388-7.007 2.33-10.556 2.913a49.07 49.07 0 0 1-3.42.443l-.511.043-.742.049a.806.806 0 0 1-.826-.478l-.037-.104-5.588-19.616a.806.806 0 1 1 1.512-.542l.038.103 5.41 18.992.344-.026.251-.023a47.465 47.465 0 0 0 3.307-.428c3.438-.564 6.915-1.477 10.21-2.816 9.339-3.794 15.371-10.171 16.475-19.784 1.105-9.613-2.793-16.499-10.132-21.192-2.588-1.655-5.43-2.913-8.311-3.823a36.183 36.183 0 0 0-2.365-.662l-.431-.102a25.57 25.57 0 0 0-.606-.13z" fill="#4285F4" fill-rule="nonzero"/><g fill="#4285F4" fill-rule="nonzero"><path d="M152.34 90.536c.23.38.11.875-.27 1.106l-3.443 2.127-.68.406-.49.283c-1.488.848-3.158 1.685-5.746 2.87l-.569.254c-1.158.505-1.873.71-2.765.739-1.447.046-2.845-.649-3.411-1.88a.804.804 0 1 1 1.408-.77l.053.096c.268.583 1.048.97 1.899.944.696-.022 1.31-.216 2.46-.732l.256-.116c2.689-1.231 4.354-2.072 5.857-2.94l.451-.265.52-.312c.554-.34 2.592-1.611 3.366-2.081a.803.803 0 0 1 1.104.27z"/><path d="M145.072 91.074a.806.806 0 0 1-.333 1.09l-3.63 1.972c-.836.448-1.504.79-2.17 1.108-1.928.919-3.64 1.517-5.47 1.857-1.122.208-2.188.11-3.06-.383-1.26-.711-1.826-2.492-.811-3.658a.803.803 0 0 1 1.134-.078c.335.292.37.8.078 1.136-.266.306-.063.942.388 1.197.502.283 1.196.347 1.977.202 1.68-.312 3.263-.865 5.073-1.727l.484-.236a59.293 59.293 0 0 0 1.936-1.01l2.845-1.551.471-.253a.804.804 0 0 1 1.088.334z"/><path d="M143.99 88.052a.806.806 0 0 1-.31 1.095l-.713.41-1.405.829c-.92.536-1.538.866-2.245 1.187-1.85.84-3.59 1.482-5.303 1.933l-.75.186-.715.166c-.634.14-1.054.204-1.551.231-1.406.08-2.565-.275-3.268-1.278-.648-.92-.53-2.234.165-3.135 1.224-1.586 3.911-2.467 7.583-2.904a.805.805 0 0 1 .19 1.6c-3.254.387-5.635 1.168-6.501 2.289-.288.373-.336.919-.122 1.224.318.453.954.647 1.863.596.446-.025.84-.09 1.529-.249l.633-.15c1.79-.428 3.615-1.083 5.583-1.976l.35-.164c.58-.278 1.156-.598 2.01-1.1l.97-.575c.368-.217.627-.366.912-.526a.803.803 0 0 1 1.094.31zm4.263-12.866a.805.805 0 0 1-.813.795c-3.483-.04-7.396.654-12.402 2.014l-.606.167c-1.284.355-1.901.552-2.54.843l-.138.064c-.477.225-.785.44-.974.692-.176.233-.227.516-.15.683.127.274.612.423 1.446.41l.718-.03 6.73-.366a.805.805 0 0 1 .068 1.609l-2.754.145-3.532.2c-.362.018-.663.033-.963.046-1.563.066-2.662-.23-3.172-1.338-.347-.75-.185-1.651.324-2.328.377-.501.881-.854 1.572-1.18.695-.329 1.291-.536 2.39-.85l.546-.153c5.433-1.507 9.646-2.283 13.456-2.238.444.005.8.37.794.815z"/><path d="M142.915 84.726c.21.392.062.88-.33 1.09-4.438 2.373-7.59 3.063-12.93 2.921-.825-.022-1.339-.085-1.886-.289-.766-.285-1.391-.839-1.654-1.57-.431-1.202.238-2.558 1.377-3.236.584-.347 1.188-.525 2.052-.654l.856-.11c4.22-.512 6.293-1.111 10.039-2.917a.806.806 0 0 1 .698 1.451c-3.594 1.733-5.781 2.42-9.528 2.935l-1.56.197c-.827.107-1.321.237-1.736.483-.531.317-.826.913-.685 1.306.088.243.348.474.7.605.337.125.71.171 1.37.189 5.07.134 7.946-.495 12.13-2.732a.804.804 0 0 1 1.087.33z"/></g><path d="M142.765 48.928a.806.806 0 0 1 1.475.646c-.578 1.314-.63 2.915-.27 4.932l.073.382c.063.317.123.59.218 1.007l.38 1.656c.312 1.414.436 2.243.471 3.256l.007.314c.002.16 0 .333-.002.54l-.016 1.037c-.001.648.026 1.024.106 1.448.173.915.67 1.642 1.244 1.851l.059.017 7.962.085c7.285.062 11.603.047 12.686-.037l.063-.006.01-.03c.035-.143.06-.348.067-.61l.003-.166c.003-.9-.166-2.256-.508-4.05a.804.804 0 0 1 1.582-.301l.12.645c.697 3.868.621 5.743-.748 6.057l-.131.023c-1.028.134-5.758.155-14.565.071l-6.666-.073-.17-.02c-1.35-.31-2.299-1.612-2.59-3.158l-.054-.314c-.067-.462-.086-.912-.08-1.618l.017-1.052c.002-.173.001-.319-.002-.46l-.004-.138c-.035-1.026-.18-1.875-.58-3.608l-.273-1.183c-.063-.279-.11-.498-.157-.728l-.028-.14c-.498-2.492-.473-4.516.301-6.275z" fill="#4285F4" fill-rule="nonzero"/><g transform="translate(161.459 2.303)"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><path d="M.031 21.66c.255-2.568 2.554-4.442 5.135-4.182a4.682 4.682 0 0 1 3.421 2.037 4.695 4.695 0 0 1-.024-1.107c.255-2.568 2.554-4.442 5.13-4.181l.028.003c.964.097 1.783-.638 1.842-1.6.008-.125.02-.251.038-.378.31-2.172 2.166-3.863 4.365-4a4.6 4.6 0 0 1 1.472.143c.975.258 1.933-.483 1.994-1.484l.21-3.452c.163-2.651 3.1-4.178 5.379-2.795 2.277 1.383 2.258 4.683-.036 6.04l-3.811 2.254a1.61 1.61 0 0 0-.644 2.053c.325.718.47 1.527.384 2.366-.256 2.563-2.555 4.436-5.13 4.181l-.03-.003c-.942-.095-1.791.605-1.839 1.546a4.692 4.692 0 0 1-5.151 4.419 4.692 4.692 0 0 1-3.423-2.037c.05.36.064.73.026 1.107-.256 2.563-2.556 4.436-5.135 4.183-2.575-.26-4.457-2.55-4.201-5.113" fill="#4285F4" mask="url(#b)"/></g><path d="M161.475 26.911a6.484 6.484 0 0 1 .733 9.17c-2.341 2.733-6.464 3.06-9.21.73a6.486 6.486 0 0 1-.733-9.17 6.554 6.554 0 0 1 9.21-.73" fill="#FFF"/><path d="M151.653 27.118a7.289 7.289 0 0 0 .823 10.305c3.084 2.618 7.715 2.25 10.344-.82a7.288 7.288 0 0 0-.823-10.305c-3.084-2.617-7.714-2.25-10.344.82zm9.3.406a5.681 5.681 0 0 1 .643 8.034 5.747 5.747 0 0 1-8.076.64 5.683 5.683 0 0 1-.643-8.035 5.748 5.748 0 0 1 7.884-.796l.193.157z" fill="#4285F4" fill-rule="nonzero"/><path d="M163.92 32.616c.85-1.668-2.037-5.655-4.051-6.672-2.014-1.018-6.642-.056-7.493 1.612 1.71 1.768 8.243 4.389 10.677 4.884l.866.176z" fill="#4285F4"/><path d="M150.526 32.93a.806.806 0 0 1 1.043.18l.063.09c.277.454.758.755 1.199.755.442 0 .862-.225 1.05-.542l.05-.098a.806.806 0 0 1 1.485.623c-.418.994-1.478 1.625-2.585 1.625-1.034 0-2.02-.616-2.575-1.529a.803.803 0 0 1 .27-1.104z" fill="#4285F4" fill-rule="nonzero"/><path d="M167.507 66.135a.805.805 0 0 1 .433 1.546l-.106.029-20.582 4.257a.805.805 0 0 1-.432-1.546l.105-.029 20.582-4.257z" fill="#4682F4" fill-rule="nonzero"/><g fill="#4285F4" fill-rule="nonzero"><path d="M95.347 77.103a.806.806 0 0 1 .962-.61.803.803 0 0 1 .609.96c-.48 2.136-1.868 4.347-3.66 5.503l-.812.482c-.59.355-.932.637-1.146.966-.101.156-.136.288-.122.348.017.073.188.191.419.21.282.025.594-.046 1.156-.249l.903-.328c5.416-1.995 8.043-3.418 9.986-5.892.551-.702.944-1.426 1.083-2.05a.806.806 0 0 1 .961-.61.803.803 0 0 1 .61.959c-.199.893-.7 1.818-1.388 2.693-2.248 2.863-5.135 4.386-11.143 6.572l-.469.17c-.768.277-1.258.389-1.84.339-.864-.074-1.65-.615-1.845-1.443-.129-.545.019-1.102.34-1.595.335-.515.773-.902 1.414-1.312l.474-.287.375-.218c1.483-.863 2.725-2.788 3.133-4.608z"/><path d="M83.987 77.326c1.354-2.038 3.087-3.135 6.81-4.776l.392-.172c4.907-2.135 8.03-3.214 11.302-3.63a.803.803 0 1 1 .201 1.596c-3.076.39-6.09 1.432-10.862 3.509l-.714.315c-3.208 1.434-4.7 2.408-5.788 4.047-.354.533-.485 1.327-.337 2.025l.664 3.258c.478 2.406.985 5.058 1.1 5.804l.012.086c.109.792.274 1.145.438 1.154.259.015.718-.6 1.018-1.502.282-.847.3-1.733.109-3.212l-.21-1.433-.089-.5c-.05-.3-.087-.59-.11-.867-.137-1.667.196-2.735.589-3.205.616-.928 1.614-1.338 3.586-1.714l1.785-.313c.724-.13 1.088-.217 1.48-.347a.804.804 0 1 1 .505 1.527l-.233.074c-.464.14-.93.237-1.847.396l-.827.142-.537.098c-1.44.277-2.2.563-2.56 1.01l-.06.081c-.175.213-.379.866-.276 2.117.013.154.03.314.054.48l.143.835.16 1.09c.265 1.893.265 3.047-.135 4.247-.517 1.553-1.354 2.675-2.64 2.602-1.18-.067-1.645-.843-1.877-2.15l-.11-.699c-.251-1.478-1.239-6.519-1.707-8.723-.234-1.107-.032-2.343.57-3.25z"/><path d="M83.462 78.295a.803.803 0 1 1 1.388.814l-1.39 2.38c-1.383 2.392-2.463 4.338-3.33 6.014l-.114.229c-.108.233-.136.355-.118.421.018.067.257.263.373.279.19.026.441-.035.728-.184.611-.317 1.142-.857 1.777-1.744.438-.611.923-1.447 1.451-2.462a.803.803 0 1 1 1.428.74c-.56 1.078-1.077 1.97-1.57 2.658-.77 1.075-1.46 1.776-2.346 2.236-.558.29-1.125.427-1.689.35-.734-.1-1.514-.737-1.707-1.45-.165-.611-.026-1.073.357-1.811l.34-.65c1.108-2.1 2.53-4.606 4.422-7.82z"/></g><path d="M57.963 76.556a1.512 1.512 0 0 1 2.027-.102l.108.098 17.27 17.198 24.354-7.42a1.51 1.51 0 0 1 1.835.866l.049.136a1.51 1.51 0 0 1-.869 1.834l-.137.049-25.22 7.683a1.51 1.51 0 0 1-1.394-.273l-.112-.101-17.91-17.836a1.506 1.506 0 0 1-.001-2.132z" fill="#4285F4" fill-rule="nonzero"/><g><path d="M73.735 27.798a.957.957 0 0 1-.899-1.087 9.21 9.21 0 0 1 9.562-7.95c4.828.22 8.699 4.061 9.082 8.793a.922.922 0 0 1-.96 1.004l-16.785-.76z" fill="#F882FF"/><path d="M46.537 44.15l-7.78 3.522c-1.1.499-1.249 1.981-.268 2.67l6.939 4.87c.98.69 2.354.068 2.473-1.118l.842-8.396c.12-1.187-1.107-2.047-2.206-1.549" fill="#D2E3FC"/><path d="M45.335 46.642c-2.101-2.484-1.676-6.184.948-8.262l11.107-8.82c2.625-2.08 6.456-1.752 8.557.732s1.677 6.184-.948 8.263l-11.106 8.82c-2.625 2.08-6.456 1.75-8.558-.733" fill="#FABD04"/><g transform="rotate(-102 42.988 6.811)"><mask id="d" fill="#fff"><use xlink:href="#c"/></mask><path d="M3.01-6.275c-.34 0-.687.118-.977.375L-4.024-.53c-.856.758-.57 2.16.514 2.523L4.162 4.56c.16.053.32.078.476.078.896 0 1.644-.83 1.45-1.785L4.472-5.084a1.484 1.484 0 0 0-1.461-1.19M2.817-4.19l1.398 6.865-6.638-2.22 5.24-4.645" fill="#FFF" mask="url(#d)"/></g><path d="M43.26 66.655l-3.847-6.7a2.573 2.573 0 0 0-2.228-1.28l-7.868-.026a2.63 2.63 0 0 0-2.261 1.264l-4.022 6.673a2.504 2.504 0 0 0-.032 2.543l3.847 6.7a2.572 2.572 0 0 0 2.228 1.28l7.868.026a2.632 2.632 0 0 0 2.262-1.264l4.02-6.672a2.503 2.503 0 0 0 .033-2.544" fill="#38A953"/><path d="M42.107 102.465h0v-.002a8.461 8.461 0 0 0-1.253-1.538l-1.343-1.65a6.942 6.942 0 0 1-1.515-5.197l.28-2.386.122-1.045-.055-.007a5.94 5.94 0 0 0-.06-.752c-.492-3.26-3.588-5.485-6.915-4.972-3.328.513-5.628 3.571-5.135 6.83.037.252.097.496.165.735l-.05.024.424.96.97 2.194a6.96 6.96 0 0 1 .088 5.417l-.795 1.98a8.491 8.491 0 0 0-.741 1.845l-.001.002h0a8.374 8.374 0 0 0-.038 4.236c1.006 4.032 4.942 6.764 9.169 6.373 5.048-.468 8.615-4.991 7.886-9.824a8.323 8.323 0 0 0-1.203-3.223z" stroke="#D2E3FC" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M40.532 135.356c-7.25-.375-12.761-6.448-12.311-13.564l.013-.21c.449-7.116 6.69-12.581 13.939-12.206 7.25.375 12.761 6.448 12.311 13.564l-.013.21c-.45 7.117-6.69 12.581-13.939 12.206" fill="#EA4335"/><g transform="rotate(-103 70.313 56.882)"><mask id="f" fill="#fff"><use xlink:href="#e"/></mask><path d="M28.924.89c-4.53.083-8.37 3.754-8.984 8.531-.727 5.66 3.137 10.797 8.463 11.23a8.667 8.667 0 0 0 3.378-.392l.274-.097.373-.145c.485-.2.925-.425 1.339-.683l.258-.17 1.826-.942a5.58 5.58 0 0 1 4.559-.274l3.188 1.201.11.034c.11.026.223.031.331.016l.02-.004.258.04c.092.013.183.022.275.03 3.737.304 6.968-2.686 7.245-6.64.278-3.947-2.488-7.413-6.216-7.717l-.31-.016h-.227l-.028-.01a.899.899 0 0 0-.324-.035l-.156.024-3.276.663-.275.048c-1.467.221-2.962-.153-4.2-1.061l-1.68-1.235-.225-.203a9.26 9.26 0 0 0-1.183-.869l-.317-.186A8.772 8.772 0 0 0 29.265.889h-.341zm.35 1.81a6.957 6.957 0 0 1 2.96.745l.296.157c.515.29.993.642 1.427 1.049l.083.068 1.714 1.26c1.723 1.265 3.848 1.744 5.905 1.328l3.01-.61.078.011.055.002.056-.001a4.46 4.46 0 0 1 .615.002c2.71.22 4.77 2.8 4.56 5.787-.21 2.979-2.592 5.184-5.294 4.964a4.622 4.622 0 0 1-.611-.097l-.111-.017-.079-.003-2.89-1.09a7.39 7.39 0 0 0-6.029.36l-1.87.968-.095.056a7.217 7.217 0 0 1-1.55.802l-.298.103a6.838 6.838 0 0 1-2.657.304c-4.266-.347-7.413-4.532-6.814-9.196.502-3.911 3.616-6.887 7.222-6.954l.316.001z" fill="#FFF" fill-rule="nonzero" mask="url(#f)"/></g></g><g><g transform="rotate(9 44.073 633.419)"><mask id="h" fill="#fff"><use xlink:href="#g"/></mask><path d="M35.644 27.522l-24.76 9.258a1.253 1.253 0 0 1-1.614-.745L.079 11.095a1.268 1.268 0 0 1 .74-1.627L25.58.21c.65-.243 1.372.09 1.614.745l9.191 24.94a1.268 1.268 0 0 1-.74 1.627" fill="#4285F4" mask="url(#h)"/></g><path d="M121.048 11.073a4.033 4.033 0 0 0-1.246.577l-.217.161c-.247.196-.47.42-.664.668l-.548.544a2.164 2.164 0 0 1-1.531.64h-1.374l-.094.007a.686.686 0 0 0-.177.052l-.072.014-.12.03a3.055 3.055 0 0 0-2.149 3.73 3.024 3.024 0 0 0 3.71 2.157l.2-.064.06-.007a.65.65 0 0 0 .13-.042l.178-.099 1.076-.625a2.152 2.152 0 0 1 1.64-.217l.815.22c.218.091.522.173.835.22.667.097 1.35.027 2-.215 1.854-.691 2.95-2.67 2.562-4.618-.461-2.313-2.759-3.742-5.014-3.133zm3.732 3.388c.263 1.322-.485 2.672-1.737 3.139a2.723 2.723 0 0 1-1.965-.019l-.888-.244a3.459 3.459 0 0 0-2.636.35l-1.052.609-.072.024a1.717 1.717 0 0 1-2.31-1.157 1.748 1.748 0 0 1 1.224-2.136l.065-.016c.045-.01.094-.018.15-.025l.069-.016 1.215-.001a3.47 3.47 0 0 0 2.456-1.024l.598-.601.106-.127a3.04 3.04 0 0 1 .4-.388l.16-.117a2.734 2.734 0 0 1 4.217 1.749zm-21.012-1.449a3.139 3.139 0 0 0-2.443 3.69 3.11 3.11 0 0 0 3.669 2.451 3.139 3.139 0 0 0 2.442-3.689 3.111 3.111 0 0 0-3.668-2.452zm2.387 2.706a1.832 1.832 0 0 1-1.422 2.155 1.803 1.803 0 0 1-2.126-1.426 1.833 1.833 0 0 1 1.422-2.155 1.803 1.803 0 0 1 2.09 1.281l.036.145z" fill="#FFF" fill-rule="nonzero"/><g transform="rotate(9 43.883 633.603)"><mask id="j" fill="#fff"><use xlink:href="#i"/></mask><path d="M13.402 18.342a.654.654 0 0 1 .782-.355l.09.035 25.268 11.894a.653.653 0 0 1-.467 1.217l-.09-.035-24.67-11.613-6.724 14.77a.654.654 0 0 1-.775.357l-.09-.033a.653.653 0 0 1-.358-.775l.034-.09 7-15.372z" fill="#FFF" fill-rule="nonzero" mask="url(#j)"/></g></g></g></svg>
\ No newline at end of file
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_settings.html b/chrome/browser/resources/nearby_share/shared/nearby_share_settings.html
index cfea57c6..a7c3461 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_share_settings.html
+++ b/chrome/browser/resources/nearby_share/shared/nearby_share_settings.html
@@ -1,5 +1,5 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html">
 
-<script src="../mojo/nearby_share_settings.mojom-lite.js"></script>
+<script src="/mojo/nearby_share_settings.mojom-lite.js"></script>
 <script src="nearby_share_settings.js"></script>
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_settings.js b/chrome/browser/resources/nearby_share/shared/nearby_share_settings.js
index 78b66d9..5fd6e04 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_share_settings.js
+++ b/chrome/browser/resources/nearby_share/shared/nearby_share_settings.js
@@ -5,7 +5,7 @@
 // clang-format off
 // #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
 // #import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
-// #import '../mojo/nearby_share_settings.mojom-lite.js';
+// #import '/mojo/nearby_share_settings.mojom-lite.js';
 // clang-format on
 
 cr.define('nearby_share', function() {
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.js b/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.js
index aa04314..689d977c 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.js
+++ b/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.js
@@ -25,7 +25,7 @@
   /** @polymerBehavior */
   /* #export */ const NearbyShareSettingsBehavior = {
     properties: {
-      /** @type {?NearbySettings} */
+      /** @type {nearby_share.NearbySettings} */
       settings: {
         type: Object,
         notify: true,
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_shared.gni b/chrome/browser/resources/nearby_share/shared/nearby_shared.gni
new file mode 100644
index 0000000..49bba74
--- /dev/null
+++ b/chrome/browser/resources/nearby_share/shared/nearby_shared.gni
@@ -0,0 +1,12 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+nearby_shared_auto_imports = [ "chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.html|NearbyShareSettingsBehavior,NearbySettings" ]
+nearby_shared_namespace_rewrites = [
+  "nearby_share.NearbySettings|NearbySettings",
+  "nearby_share.NearbyShareSettingsBehavior|NearbyShareSettingsBehavior",
+  "nearby_share.getNearbyShareSettings|getNearbyShareSettings",
+  "nearby_share.observeNearbyShareSettings|observeNearbyShareSettings",
+  "nearby_share.setNearbyShareSettingsForTesting|setNearbyShareSettingsForTesting",
+]
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.html b/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.html
index 7c1563f..9242145 100644
--- a/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.html
+++ b/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.html
@@ -29,5 +29,19 @@
         <path d="M16.1839 13.9904C17.3593 13.0152 18.298 11.6851 19.0002 10C17.0002 6.00003 14.0002 4.00003 10.0002 4.00003C8.81854 4.00003 7.7242 4.17455 6.71711 4.5236L8.34623 6.15272C8.86951 6.05045 9.42035 6.00003 10.0002 6.00003C12.9375 6.00003 15.1317 7.29405 16.7643 10.0696C16.2217 11.117 15.5593 11.9465 14.7617 12.5682L16.1839 13.9904Z" fill="#1A73E8"></path>
         <path d="M12.9133 10.7198L9.28043 7.08692C9.511 7.03014 9.75206 7.00003 10.0002 7.00003C11.657 7.00003 13.0002 8.34317 13.0002 10C13.0002 10.2481 12.97 10.4892 12.9133 10.7198Z" fill="#1A73E8"></path>
       </g>
+    </defs>
+  </svg>
+</iron-iconset-svg>
+
+<iron-iconset-svg name="nearby-images" size="200">
+  <svg>
+    <defs>
+      <g id="nearby-device-visibility" fill="none" fill-rule="evenodd">
+        <path d="M0 0h200v200H0z"></path><path d="M150.441 100.728c0 26.949-21.772 48.794-48.63 48.794-26.858 0-48.63-21.845-48.63-48.794 0-26.95 21.772-48.795 48.63-48.795 26.858 0 48.63 21.845 48.63 48.795" fill="#D2E3FC"></path><path d="M176.711 53.44l-12.39-3.317a1.021 1.021 0 0 1-.722-1.25l3.32-12.383a1.022 1.022 0 0 1 1.252-.722l12.39 3.317c.544.146.868.707.722 1.251l-3.32 12.383a1.022 1.022 0 0 1-1.252.722" fill="#34A853"></path><path d="M31.832 148.371l-9.514 5.538c-3.553 2.068-4.77 6.644-2.72 10.223 2.053 3.584 6.603 4.813 10.161 2.742l9.514-5.538c3.48-2.026 4.718-6.454 2.844-9.998l-.124-.225c-2.053-3.584-6.603-4.813-10.161-2.742zm8.425 3.736c1.505 2.627.612 5.986-1.99 7.5l-9.514 5.539c-2.597 1.511-5.918.614-7.42-2.008-1.504-2.627-.61-5.986 1.991-7.5l9.514-5.539c2.529-1.471 5.743-.66 7.297 1.804l.122.204z" fill="#EA4335" fill-rule="nonzero"></path><path d="M26.693 54.6l-5.899-5.896a2.743 2.743 0 0 1-.711-2.653l2.159-8.054a2.745 2.745 0 0 1 1.943-1.941l8.058-2.158a2.75 2.75 0 0 1 2.655.71l5.9 5.896c.693.694.965 1.705.71 2.653L39.35 51.21a2.746 2.746 0 0 1-1.943 1.942l-8.058 2.158a2.751 2.751 0 0 1-2.655-.71" fill="#FBBC05"></path><path d="M26.536 141.312l-5.553-4.145a.552.552 0 0 1-.113-.773l4.149-5.55a.552.552 0 0 1 .773-.112l5.554 4.145a.552.552 0 0 1 .112.773l-4.149 5.55a.552.552 0 0 1-.773.112" fill="#F882FF"></path><path d="M102.004 29.332c-39.453 0-71.437 31.965-71.437 71.396 0 39.43 31.984 71.395 71.437 71.395 39.453 0 71.437-31.965 71.437-71.395 0-39.431-31.983-71.396-71.437-71.396zm0 2c38.35 0 69.437 31.07 69.437 69.396s-31.088 69.395-69.437 69.395-69.437-31.07-69.437-69.395c0-38.326 31.088-69.396 69.437-69.396z" fill="#4285F4" fill-rule="nonzero"></path><path d="M104.18 73.085a8.864 8.864 0 0 0-4.738 0l-19.099 7.12c-1.232.342-2.075 1.387-2.075 2.572v14.13c0 11.668 5.686 22.805 15.688 29.978 3.332 2.39 6.297 3.737 7.855 3.737 1.558 0 4.523-1.348 7.855-3.737 10.003-7.173 15.688-18.31 15.688-29.977V82.777c0-1.185-.842-2.23-2.075-2.573l-19.099-7.12z" fill="#4285F4"></path><path d="M101.768 94.59c-3.19 0-5.789 2.668-5.789 5.945 0 3.276 2.599 5.945 5.79 5.945 3.19 0 5.789-2.669 5.789-5.945 0-3.277-2.6-5.945-5.79-5.945zm-.193 9.115c-1.81 0-3.28-1.51-3.28-3.368 0-1.86 1.47-3.37 3.28-3.37 1.81 0 3.281 1.51 3.281 3.37 0 1.859-1.47 3.368-3.28 3.368zm.193-12.682c-6.14 0-11.384 3.944-13.508 9.512 2.124 5.567 7.368 9.512 13.508 9.512 6.14 0 11.384-3.945 13.509-9.512-2.125-5.568-7.368-9.512-13.509-9.512zm-.193 16.646c-4.726 0-8.942-2.763-11-7.134 2.058-4.371 6.274-7.134 11-7.134 4.727 0 8.942 2.763 11 7.134-2.058 4.37-6.273 7.134-11 7.134z" fill="#FFF" fill-rule="nonzero"></path>
+      </g>
+
+      <path id="a" d="M.008.144h30.71v26.652H.007z"/><path d="M3.798.549A5.982 5.982 0 0 0 .812 8.458l5.764 12.741a5.97 5.97 0 0 0 7.9 2.99 5.982 5.982 0 0 0 2.987-7.909L11.697 3.54A5.96 5.96 0 0 0 3.798.55" id="c"/><path d="M1.258 10.212c-1.955 7.205 1.886 14.751 8.58 16.855l.196.063c6.694 2.104 13.705-2.03 15.66-9.234C27.65 10.691 23.81 3.145 17.117 1.04L16.92.978a11.78 11.78 0 0 0-3.546-.549C7.907.43 2.868 4.28 1.258 10.212z" id="e"/><path id="g" d="M0 .13h36.463v36.73H0z"/><path d="M25.094.245L.89 9.568c-.687.265-1.037 1.056-.782 1.769l8.985 25.114c.255.712 1.018 1.075 1.704.811L35 27.939c.687-.265 1.037-1.056.782-1.769L26.798 1.056A1.329 1.329 0 0 0 25.555.16c-.153 0-.31.028-.461.086" id="i"/>
+      <g id="nearby-onboarding-splash" fill="none" fill-rule="evenodd"><path d="M0 0h200v200H0z"/><path d="M110.893 164.142l-6.065 12.062c1.606.235 2.96.506 4.06.814 4.544 1.27 10.262 2.852 15.561 5.64 7.226 3.802 10.566 4.087 10.02.856-3.964-3.923-4.913-5.674-2.848-5.254 2.065.42 5.403 1.107 10.015 2.062.624-.243.804-.791.539-1.644-.208-.67-3.266-2.054-4.064-3.237-.146-.216.396-.215 1.624.003 2.632.41 4.12.547 4.465.41 1.163-.466-.097-2.017-.003-2.827.054-.468.801-.549 1.216-.806.288-.179.267-.554.36-.741.42-.842-3.068-1.44-2.8-2.494.274-1.075 4.274-2.606 1.607-3.406-5.282-1.583-10.813.808-16.629.56-3.877-.166-9.563-.832-17.058-1.998z" fill="#D2E3FC"/><path d="M141.354 171.58l.57.095 1.311.246c1.522.274 1.905.19 2.129-.434.02-.056-.109-.25-.638-.581-.664-.415-1.721-.839-3.074-1.237a.805.805 0 1 1 .454-1.543l.57.174c3.14.992 4.78 2.126 4.204 3.732-.561 1.563-1.636 1.851-3.696 1.512l-1.341-.249c-.275-.05-.504-.09-.735-.126a12.992 12.992 0 0 0-2.067-.174 32.862 32.862 0 0 0-4.908.396.806.806 0 0 1-.92-.672.803.803 0 0 1 .673-.918 34.47 34.47 0 0 1 5.148-.414c.753-.002 1.497.064 2.32.193z" fill="#4682F4" fill-rule="nonzero"/><path d="M134.892 176.05a.803.803 0 1 1 .003-1.609l1.163.008c.546.006.966.015 1.232.028l.092.005a18.507 18.507 0 0 1 2.379.322l.654.138c.519.115 1.48.336 1.707.384l.395.079c1.162.217 1.48.119 1.591-.306.206-.791-.878-1.532-3.807-2.045a.804.804 0 1 1 .276-1.585c3.753.658 5.634 1.944 5.09 4.037-.428 1.64-1.63 1.868-3.876 1.394l-1.942-.436a18.28 18.28 0 0 0-2.16-.345l-.401-.031-.424-.016a88.28 88.28 0 0 0-1.972-.022z" fill="#4682F4" fill-rule="nonzero"/><path d="M141.644 179.567c.18-.31.013-.618-.823-1.159-1.14-.736-3.19-1.51-6.125-2.293a.806.806 0 0 1-.571-.986.803.803 0 0 1 .984-.57c3.084.825 5.27 1.649 6.583 2.498 1.565 1.01 2.102 2.273 1.225 3.504-.514.722-1.262.731-2.752.368l-.552-.143c-.57-.153-1.557-.428-1.585-.435a32.331 32.331 0 0 0-2.211-.532 19.356 19.356 0 0 0-1.642-.258c-1.193-.132-2.08-.185-2.641-.16l-.234.016-.035.06a.798.798 0 0 1-.223.222l-.095.054a.805.805 0 0 1-1.075-.374c-.503-1.04.296-1.495 1.408-1.576.672-.05 1.687.005 3.07.158.58.065 1.169.158 1.778.28.61.12 1.21.262 1.896.443l2.295.625c.494.126.85.198 1.108.22l.186.012c.018.002.028.006.031.013v.013zm-13.848-1.352a.806.806 0 0 1-1.006-.534c-.452-1.475-.264-2.833.571-3.995.9-1.253 2.656-2.153 5.813-3.27l3.54-1.22.187-.068c.695-.257 1.397-.438 2.698-.713l1.718-.36c1.35-.292 2.061-.494 2.677-.773.748-.34.941-.604.836-.965-.172-.587-3.21-.75-7.838-.247l-.935.106c-.32.038-.647.079-.985.122l-5.142.7c-.596.077-1.065.135-1.254.15-2.193.181-7.982-.704-17.529-2.658a.804.804 0 1 1 .323-1.576l2.02.409c8.168 1.631 13.228 2.373 15.054 2.223l.305-.033c1.269-.15 5.264-.712 5.497-.742l1.029-.132c.332-.04.656-.08.973-.116l1.221-.13c5.403-.544 8.286-.313 8.807 1.474.376 1.29-.324 2.248-1.715 2.88l-.285.122c-.624.255-1.323.45-2.45.7l-2.466.52c-.771.17-1.286.304-1.735.454l-1.52.534c-1.005.347-2.173.743-2.13.728-3.045 1.058-4.745 1.9-5.405 2.818-.533.743-.649 1.579-.34 2.588a.804.804 0 0 1-.534 1.004z" fill="#4682F4" fill-rule="nonzero"/><path d="M135.161 182.503c.791 1.153.728 2.38-.312 3.488-1.426 1.52-4.087.752-10.188-2.074l-3.96-1.853a66.2 66.2 0 0 0-2.227-.987c-3.772-1.591-8.276-2.854-13.51-3.787a.806.806 0 0 1-.652-.933.803.803 0 0 1 .932-.652c5.064.903 9.474 2.113 13.233 3.632l.62.257c.83.349 1.486.641 2.657 1.185l3.215 1.507 1.046.481c4.608 2.09 7.048 2.774 7.66 2.122.511-.545.531-.935.16-1.477-.356-.519-.985-1.053-2.102-1.825l-.786-.532c-1.524-1.024-2.835-2.028-3.934-3.013a.805.805 0 1 1 1.072-1.198 33.243 33.243 0 0 0 3.277 2.548l1.027.695c1.343.913 2.13 1.548 2.662 2.262l.11.154z" fill="#4682F4" fill-rule="nonzero"/><path d="M92.163 196.078c.982.182 2.643.273 3.633.406.83.112 1.619-.175 2.423-.405.803-.232.747-.847.919-1.664.695-.113 1.406-.232 2.02-.574.616-.342 1.125-.96 1.137-1.661.007-.395-.558-.19-.444-.568.073-.236.66-1.04.785-1.255.527-.906.161-2.213-.76-2.716.363-.226.476-.726.358-1.135-.118-.409-.42-.74-.742-1.018-2.532-2.183-6.36-1.812-9.443-3.116.583-.446 1.347-.564 2.022-.851.675-.287 1.338-.898 1.241-1.624-.073-.554-.585-.969-1.125-1.117-.542-.148-1.115-.088-1.674-.049-3.745.265-7.532-.417-11.249.108-.252.037-.515.083-.717.238-.27.21-3.883-1.106-3.963-.774-.482 1.974-7.031-4.966-7.839-4.154-.807.812-11.512 9.186-11.706 10.15-.164.811 14.052 7.893 15.264 8.424 2.096.917 12.76 2.606 14.612 2.948 1.548.287 3.7.12 5.248.407z" fill="#D2E3FC"/><path d="M87.628 192.91a.806.806 0 0 1 .445-1.548c4.335 1.25 7.827 1.874 10.84 1.8.923-.021 1.458-.12 1.76-.356.22-.172.26-.694.048-.846a.806.806 0 0 1-.184-1.124.803.803 0 0 1 1.122-.185c1.153.829 1.014 2.634.003 3.425-.67.523-1.447.667-2.71.697-3.209.078-6.845-.572-11.324-1.863zm-.619-10.486a.806.806 0 0 1 .433-1.551l.341.091c1.706.442 6.23 1.446 7.773 1.731.713.132 1.388.288 2.361.538l.836.219c1.116.292 1.938.623 2.638 1.14.524.388.923.874 1.114 1.442.183.543.153 1.141-.125 1.632-.527.932-1.542 1.258-2.914 1.245a10.974 10.974 0 0 1-1.039-.064l-1.324-.156c-.403-.053-.82-.12-1.435-.226l-1.496-.259-1.511-.258a35.12 35.12 0 0 1-3.64-.82.806.806 0 0 1 .433-1.552c1.282.359 2.228.567 3.841.848l3.05.523c.51.085.867.137 1.248.183l.719.084c.47.055.826.083 1.169.086.843.008 1.344-.153 1.5-.428.038-.067.044-.192 0-.324-.074-.22-.266-.454-.545-.66-.445-.328-1.011-.573-1.789-.795l-.8-.214-.913-.233c-.55-.136-1-.238-1.446-.324l-.639-.122c-2.01-.396-6.554-1.415-7.84-1.776z" fill="#4285F4" fill-rule="nonzero"/><path d="M88.364 189.969a.806.806 0 0 1 .423-1.554c2.262.617 6.487 1.543 8.684 1.896 1.54.248 2.447.295 3.257.092.322-.081.51-.183.722-.395.12-.119.2-.406.171-.674-.037-.348-.215-.568-.462-.665l-.096-.03a.806.806 0 0 1 .39-1.563c.924.232 1.649.99 1.767 2.084.078.723-.14 1.497-.636 1.99-.425.423-.87.666-1.466.815-1.087.273-2.155.217-3.902-.064-2.255-.362-6.536-1.3-8.852-1.932zm-20.049-15.742a.806.806 0 0 1-.207-1.12.803.803 0 0 1 1.118-.207l.719.491c5.425 3.677 8.916 5.295 10.089 4.886 1.98-.69 3.677-.83 6.624-.68l4.398.28.608.03.294-.001.671-.012c.994-.007 1.669.11 2.315.521.71.453 1.16 1.257 1.056 2.078-.074.587-.414 1.102-.902 1.477-.446.344-1.076.6-1.943.84l-.503.13c-.52.126-1.46.338-1.569.365a.805.805 0 0 1-.394-1.562l1.556-.361.211-.052c.82-.212 1.391-.428 1.662-.637.172-.132.272-.284.287-.401.02-.154-.107-.38-.325-.518-.287-.183-.648-.259-1.235-.268l-.204-.001-.804.013c-.117 0-.213 0-.312-.004l-1.364-.076-2.767-.185c-3.14-.198-4.788-.125-6.595.465l-.237.08c-1.954.681-5.89-1.188-12.247-5.571zm-11.4 11.051a.806.806 0 0 1 .89-1.342c5.989 3.979 11.392 6.766 16.202 8.364l.532.172c3.514 1.113 6.104 1.57 11.318 2.09l4.4.419c1.719.173 2.897.325 4.1.538l.242.044c1.209.22 1.785.266 2.39.132.619-.137 1.118-.537 1.264-.985l.028-.113a.804.804 0 1 1 1.581.295c-.221 1.193-1.273 2.098-2.527 2.376-.756.167-1.398.149-2.457-.022l-1.265-.22c-1.168-.191-2.397-.337-4.238-.513l-2.742-.256c-5.96-.571-8.723-1.028-12.579-2.25-5.1-1.614-10.81-4.525-17.139-8.73z" fill="#4285F4" fill-rule="nonzero"/><g fill-rule="nonzero"><path d="M78.868 136.46l-.531.008c-.323.008-.621.021-.894.039l-.49.038-.12.016-9.915.101-.382-.018c-3.068-.115-6.78.197-10.366 1.302-2.21.682-4.172 1.626-5.815 2.868-3.822 2.89-5.187 7.466-6.244 17.638-.966 9.309 1.07 16.723 5.068 22.384a24.107 24.107 0 0 0 3.667 4.132c.76.675 1.36 1.117 1.72 1.34.266.167.602.16.861-.005l.093-.07 14.23-12.368c.335-.292.37-.8.078-1.135a.806.806 0 0 0-1.049-.144l-.087.066-13.753 11.953-.117-.088c-.21-.16-.432-.341-.667-.542l-.24-.209a22.505 22.505 0 0 1-3.42-3.857c-3.777-5.348-5.707-12.376-4.781-21.291l.161-1.49c.988-8.676 2.303-12.65 5.453-15.032 1.481-1.12 3.276-1.983 5.318-2.613 3.194-.985 6.534-1.306 9.34-1.247l.704.024.18.009 10.07-.106.264-.026.102-.008c.311-.025.67-.044 1.071-.054a25.64 25.64 0 0 1 3.7.18c3.7.447 7.071 1.653 9.76 3.825 1.895 1.531 3.246 3.777 4.756 7.685l.373.991c.454 1.273 3.058 8.852 4.112 11.6a.805.805 0 0 0 .544.49l.109.02 8.336 1.035-7.493 14.353-.253-.054c-2.408-.554-5.444-2.118-9.083-4.702l-.422-.302c-4.065-2.937-5.343-7.106-3.845-12.686a.806.806 0 0 0-1.556-.416c-1.663 6.198-.174 11.06 4.457 14.405 4.444 3.21 8.108 5.03 11.03 5.445a.81.81 0 0 0 .77-.329l.058-.096 8.3-15.901a.804.804 0 0 0-.513-1.15l-.101-.02-9.004-1.117-.494-1.347a368.1 368.1 0 0 1-.94-2.636l-2.547-7.277c-1.739-4.697-3.268-7.372-5.58-9.24-2.953-2.386-6.604-3.692-10.58-4.173a27.422 27.422 0 0 0-3.403-.198z" fill="#4285F4"/><path d="M61.551 153.314l-.1.002a.805.805 0 0 0-.742.764l.002.1 1.185 15.019a.802.802 0 0 0 .285.552l.087.064 6.522 4.123a.803.803 0 1 0 .95-1.294l-.088-.065-6.18-3.908-1.156-14.617a.805.805 0 0 0-.657-.728l-.108-.012z" fill="#4682F4"/><path d="M63.276 165.48a.805.805 0 0 0-.101 1.601l.101.007h22.233a.805.805 0 0 0 .101-1.602l-.1-.006H63.275z" fill="#4682F4"/></g><path d="M69.765 131.356h5.865l1.533 6.908c-.569 1.266-2.293 2.186-4.332 2.186-2.094 0-3.855-.97-4.376-2.287l1.31-6.807z" fill="#CFE3FF"/><path d="M75.63 130.552h-5.865a.805.805 0 0 0-.791.652l-1.31 6.807a.803.803 0 0 0 .042.447c.666 1.684 2.762 2.796 5.125 2.796 2.296 0 4.343-1.05 5.067-2.661a.803.803 0 0 0 .051-.503l-1.533-6.908a.805.805 0 0 0-.786-.63zm-.647 1.608l1.329 5.987-.027.046c-.557.839-1.897 1.453-3.454 1.453l-.228-.004c-1.506-.058-2.771-.69-3.272-1.52l-.036-.065 1.135-5.897h4.553z" fill="#4285F4" fill-rule="nonzero"/><path d="M76.445 122.877a6.147 6.147 0 0 1 .694 8.688 6.202 6.202 0 0 1-8.72.692 6.147 6.147 0 0 1-.694-8.689 6.202 6.202 0 0 1 8.72-.69z" fill="#CFE3FF"/><path d="M67.112 123.046a6.95 6.95 0 0 0 .785 9.823 7.008 7.008 0 0 0 9.855-.781 6.95 6.95 0 0 0-.785-9.823 7.008 7.008 0 0 0-9.855.781zm8.811.444a5.344 5.344 0 0 1 .604 7.553 5.396 5.396 0 0 1-7.587.601 5.344 5.344 0 0 1-.603-7.553 5.396 5.396 0 0 1 7.586-.601z" fill="#4285F4" fill-rule="nonzero"/><path fill="#4285F4" d="M66.246 124.853h11.057l-.299-2.25-4.155-1.117-2.297.041-2.571 1.65z"/><path d="M81.62 121.472c-.335.523-.8 1.009-1.21 1.469l-1.697 1.912h-6.757l2.306-2.545c1.127-1.244 1.971-2.238 3.384-3.065 1.483-.869 3.377-1.116 4.163.034l.024.037c.355.55.274 1.401-.212 2.158" fill="#0F3EC1"/><path d="M69.625 127.974c.4-.082.79.147.921.52l.03.106c.083.405.424.766.824.886l.121.03a.804.804 0 1 1-.275 1.584 2.827 2.827 0 0 1-2.249-2.178.804.804 0 0 1 .628-.948z" fill="#4285F4" fill-rule="nonzero"/><g transform="translate(87.766 169.167)"><path d="M0 12.79L2.687 1.536A2 2 0 0 1 4.632 0h11.823a2 2 0 0 1 1.928 2.533l-3.88 14.02L0 12.79z" fill="#4682F4"/><ellipse fill="#FFF" cx="6.285" cy="2.818" rx="1.007" ry="1.001"/></g><path d="M89.666 149.902c.488.11.795.595.685 1.082l-.412 1.874a39.22 39.22 0 0 0-.172.87 23.414 23.414 0 0 0-.372 2.834c-.129 2.02-.374 3.896-.757 5.674-.484 2.245-1.087 3.591-2.423 4.63a.907.907 0 0 1-1.271-.159.904.904 0 0 1 .158-1.27c.909-.706 1.363-1.72 1.764-3.582.318-1.475.537-3.028.67-4.69l.05-.72c.053-.81.153-1.625.303-2.51l.154-.84c.123-.641.252-1.23.54-2.509a.906.906 0 0 1 .97-.702l.113.018zM159.996 35.664h-5.559a.805.805 0 0 0-.737.48l-1.71 3.862a.804.804 0 0 0 .734 1.13l9.034.036a.804.804 0 0 0 .737-1.135l-1.765-3.9a.805.805 0 0 0-.734-.473zm-.522 1.608l1.036 2.286-6.55-.027 1.001-2.26h4.513z" fill="#4285F4" fill-rule="nonzero"/><path d="M161.948 41.21l-.376-.071-1.578.03c-2.899.047-5.226.04-6.982-.021l-.323-.012c-12.927-.517-20.131 5.42-29.147 22.158a.804.804 0 0 1-.397.36l-.105.036-19.632 5.21 5.93 13.082.087.008c7.582.697 14.44-1.076 20.608-5.325l.439-.308c6.424-4.572 10.44-10.685 12.07-18.37a.805.805 0 0 1 1.576.333c-1.714 8.08-5.959 14.541-12.71 19.347-6.75 4.804-14.327 6.763-22.696 5.868a.806.806 0 0 1-.599-.374l-.05-.094-6.515-14.37a.803.803 0 0 1 .427-1.074l.1-.034 20.214-5.364.112-.206c8.97-16.498 16.507-22.78 29.546-22.514l1.744.054c1.767.045 4.052.043 6.855-.007l1.075-.021.147.01.31.056.39.08c.139.028.286.06.443.096.888.203 1.871.466 2.924.799 3.008.95 5.976 2.264 8.694 4.002 7.825 5.004 12.045 12.458 10.865 22.73-1.18 10.273-7.632 17.093-17.468 21.09-3.416 1.388-7.007 2.33-10.556 2.913a49.07 49.07 0 0 1-3.42.443l-.511.043-.742.049a.806.806 0 0 1-.826-.478l-.037-.104-5.588-19.616a.806.806 0 1 1 1.512-.542l.038.103 5.41 18.992.344-.026.251-.023a47.465 47.465 0 0 0 3.307-.428c3.438-.564 6.915-1.477 10.21-2.816 9.339-3.794 15.371-10.171 16.475-19.784 1.105-9.613-2.793-16.499-10.132-21.192-2.588-1.655-5.43-2.913-8.311-3.823a36.183 36.183 0 0 0-2.365-.662l-.431-.102a25.57 25.57 0 0 0-.606-.13z" fill="#4285F4" fill-rule="nonzero"/><g fill="#4285F4" fill-rule="nonzero"><path d="M152.34 90.536c.23.38.11.875-.27 1.106l-3.443 2.127-.68.406-.49.283c-1.488.848-3.158 1.685-5.746 2.87l-.569.254c-1.158.505-1.873.71-2.765.739-1.447.046-2.845-.649-3.411-1.88a.804.804 0 1 1 1.408-.77l.053.096c.268.583 1.048.97 1.899.944.696-.022 1.31-.216 2.46-.732l.256-.116c2.689-1.231 4.354-2.072 5.857-2.94l.451-.265.52-.312c.554-.34 2.592-1.611 3.366-2.081a.803.803 0 0 1 1.104.27z"/><path d="M145.072 91.074a.806.806 0 0 1-.333 1.09l-3.63 1.972c-.836.448-1.504.79-2.17 1.108-1.928.919-3.64 1.517-5.47 1.857-1.122.208-2.188.11-3.06-.383-1.26-.711-1.826-2.492-.811-3.658a.803.803 0 0 1 1.134-.078c.335.292.37.8.078 1.136-.266.306-.063.942.388 1.197.502.283 1.196.347 1.977.202 1.68-.312 3.263-.865 5.073-1.727l.484-.236a59.293 59.293 0 0 0 1.936-1.01l2.845-1.551.471-.253a.804.804 0 0 1 1.088.334z"/><path d="M143.99 88.052a.806.806 0 0 1-.31 1.095l-.713.41-1.405.829c-.92.536-1.538.866-2.245 1.187-1.85.84-3.59 1.482-5.303 1.933l-.75.186-.715.166c-.634.14-1.054.204-1.551.231-1.406.08-2.565-.275-3.268-1.278-.648-.92-.53-2.234.165-3.135 1.224-1.586 3.911-2.467 7.583-2.904a.805.805 0 0 1 .19 1.6c-3.254.387-5.635 1.168-6.501 2.289-.288.373-.336.919-.122 1.224.318.453.954.647 1.863.596.446-.025.84-.09 1.529-.249l.633-.15c1.79-.428 3.615-1.083 5.583-1.976l.35-.164c.58-.278 1.156-.598 2.01-1.1l.97-.575c.368-.217.627-.366.912-.526a.803.803 0 0 1 1.094.31zm4.263-12.866a.805.805 0 0 1-.813.795c-3.483-.04-7.396.654-12.402 2.014l-.606.167c-1.284.355-1.901.552-2.54.843l-.138.064c-.477.225-.785.44-.974.692-.176.233-.227.516-.15.683.127.274.612.423 1.446.41l.718-.03 6.73-.366a.805.805 0 0 1 .068 1.609l-2.754.145-3.532.2c-.362.018-.663.033-.963.046-1.563.066-2.662-.23-3.172-1.338-.347-.75-.185-1.651.324-2.328.377-.501.881-.854 1.572-1.18.695-.329 1.291-.536 2.39-.85l.546-.153c5.433-1.507 9.646-2.283 13.456-2.238.444.005.8.37.794.815z"/><path d="M142.915 84.726c.21.392.062.88-.33 1.09-4.438 2.373-7.59 3.063-12.93 2.921-.825-.022-1.339-.085-1.886-.289-.766-.285-1.391-.839-1.654-1.57-.431-1.202.238-2.558 1.377-3.236.584-.347 1.188-.525 2.052-.654l.856-.11c4.22-.512 6.293-1.111 10.039-2.917a.806.806 0 0 1 .698 1.451c-3.594 1.733-5.781 2.42-9.528 2.935l-1.56.197c-.827.107-1.321.237-1.736.483-.531.317-.826.913-.685 1.306.088.243.348.474.7.605.337.125.71.171 1.37.189 5.07.134 7.946-.495 12.13-2.732a.804.804 0 0 1 1.087.33z"/></g><path d="M142.765 48.928a.806.806 0 0 1 1.475.646c-.578 1.314-.63 2.915-.27 4.932l.073.382c.063.317.123.59.218 1.007l.38 1.656c.312 1.414.436 2.243.471 3.256l.007.314c.002.16 0 .333-.002.54l-.016 1.037c-.001.648.026 1.024.106 1.448.173.915.67 1.642 1.244 1.851l.059.017 7.962.085c7.285.062 11.603.047 12.686-.037l.063-.006.01-.03c.035-.143.06-.348.067-.61l.003-.166c.003-.9-.166-2.256-.508-4.05a.804.804 0 0 1 1.582-.301l.12.645c.697 3.868.621 5.743-.748 6.057l-.131.023c-1.028.134-5.758.155-14.565.071l-6.666-.073-.17-.02c-1.35-.31-2.299-1.612-2.59-3.158l-.054-.314c-.067-.462-.086-.912-.08-1.618l.017-1.052c.002-.173.001-.319-.002-.46l-.004-.138c-.035-1.026-.18-1.875-.58-3.608l-.273-1.183c-.063-.279-.11-.498-.157-.728l-.028-.14c-.498-2.492-.473-4.516.301-6.275z" fill="#4285F4" fill-rule="nonzero"/><g transform="translate(161.459 2.303)"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><path d="M.031 21.66c.255-2.568 2.554-4.442 5.135-4.182a4.682 4.682 0 0 1 3.421 2.037 4.695 4.695 0 0 1-.024-1.107c.255-2.568 2.554-4.442 5.13-4.181l.028.003c.964.097 1.783-.638 1.842-1.6.008-.125.02-.251.038-.378.31-2.172 2.166-3.863 4.365-4a4.6 4.6 0 0 1 1.472.143c.975.258 1.933-.483 1.994-1.484l.21-3.452c.163-2.651 3.1-4.178 5.379-2.795 2.277 1.383 2.258 4.683-.036 6.04l-3.811 2.254a1.61 1.61 0 0 0-.644 2.053c.325.718.47 1.527.384 2.366-.256 2.563-2.555 4.436-5.13 4.181l-.03-.003c-.942-.095-1.791.605-1.839 1.546a4.692 4.692 0 0 1-5.151 4.419 4.692 4.692 0 0 1-3.423-2.037c.05.36.064.73.026 1.107-.256 2.563-2.556 4.436-5.135 4.183-2.575-.26-4.457-2.55-4.201-5.113" fill="#4285F4" mask="url(#b)"/></g><path d="M161.475 26.911a6.484 6.484 0 0 1 .733 9.17c-2.341 2.733-6.464 3.06-9.21.73a6.486 6.486 0 0 1-.733-9.17 6.554 6.554 0 0 1 9.21-.73" fill="#FFF"/><path d="M151.653 27.118a7.289 7.289 0 0 0 .823 10.305c3.084 2.618 7.715 2.25 10.344-.82a7.288 7.288 0 0 0-.823-10.305c-3.084-2.617-7.714-2.25-10.344.82zm9.3.406a5.681 5.681 0 0 1 .643 8.034 5.747 5.747 0 0 1-8.076.64 5.683 5.683 0 0 1-.643-8.035 5.748 5.748 0 0 1 7.884-.796l.193.157z" fill="#4285F4" fill-rule="nonzero"/><path d="M163.92 32.616c.85-1.668-2.037-5.655-4.051-6.672-2.014-1.018-6.642-.056-7.493 1.612 1.71 1.768 8.243 4.389 10.677 4.884l.866.176z" fill="#4285F4"/><path d="M150.526 32.93a.806.806 0 0 1 1.043.18l.063.09c.277.454.758.755 1.199.755.442 0 .862-.225 1.05-.542l.05-.098a.806.806 0 0 1 1.485.623c-.418.994-1.478 1.625-2.585 1.625-1.034 0-2.02-.616-2.575-1.529a.803.803 0 0 1 .27-1.104z" fill="#4285F4" fill-rule="nonzero"/><path d="M167.507 66.135a.805.805 0 0 1 .433 1.546l-.106.029-20.582 4.257a.805.805 0 0 1-.432-1.546l.105-.029 20.582-4.257z" fill="#4682F4" fill-rule="nonzero"/><g fill="#4285F4" fill-rule="nonzero"><path d="M95.347 77.103a.806.806 0 0 1 .962-.61.803.803 0 0 1 .609.96c-.48 2.136-1.868 4.347-3.66 5.503l-.812.482c-.59.355-.932.637-1.146.966-.101.156-.136.288-.122.348.017.073.188.191.419.21.282.025.594-.046 1.156-.249l.903-.328c5.416-1.995 8.043-3.418 9.986-5.892.551-.702.944-1.426 1.083-2.05a.806.806 0 0 1 .961-.61.803.803 0 0 1 .61.959c-.199.893-.7 1.818-1.388 2.693-2.248 2.863-5.135 4.386-11.143 6.572l-.469.17c-.768.277-1.258.389-1.84.339-.864-.074-1.65-.615-1.845-1.443-.129-.545.019-1.102.34-1.595.335-.515.773-.902 1.414-1.312l.474-.287.375-.218c1.483-.863 2.725-2.788 3.133-4.608z"/><path d="M83.987 77.326c1.354-2.038 3.087-3.135 6.81-4.776l.392-.172c4.907-2.135 8.03-3.214 11.302-3.63a.803.803 0 1 1 .201 1.596c-3.076.39-6.09 1.432-10.862 3.509l-.714.315c-3.208 1.434-4.7 2.408-5.788 4.047-.354.533-.485 1.327-.337 2.025l.664 3.258c.478 2.406.985 5.058 1.1 5.804l.012.086c.109.792.274 1.145.438 1.154.259.015.718-.6 1.018-1.502.282-.847.3-1.733.109-3.212l-.21-1.433-.089-.5c-.05-.3-.087-.59-.11-.867-.137-1.667.196-2.735.589-3.205.616-.928 1.614-1.338 3.586-1.714l1.785-.313c.724-.13 1.088-.217 1.48-.347a.804.804 0 1 1 .505 1.527l-.233.074c-.464.14-.93.237-1.847.396l-.827.142-.537.098c-1.44.277-2.2.563-2.56 1.01l-.06.081c-.175.213-.379.866-.276 2.117.013.154.03.314.054.48l.143.835.16 1.09c.265 1.893.265 3.047-.135 4.247-.517 1.553-1.354 2.675-2.64 2.602-1.18-.067-1.645-.843-1.877-2.15l-.11-.699c-.251-1.478-1.239-6.519-1.707-8.723-.234-1.107-.032-2.343.57-3.25z"/><path d="M83.462 78.295a.803.803 0 1 1 1.388.814l-1.39 2.38c-1.383 2.392-2.463 4.338-3.33 6.014l-.114.229c-.108.233-.136.355-.118.421.018.067.257.263.373.279.19.026.441-.035.728-.184.611-.317 1.142-.857 1.777-1.744.438-.611.923-1.447 1.451-2.462a.803.803 0 1 1 1.428.74c-.56 1.078-1.077 1.97-1.57 2.658-.77 1.075-1.46 1.776-2.346 2.236-.558.29-1.125.427-1.689.35-.734-.1-1.514-.737-1.707-1.45-.165-.611-.026-1.073.357-1.811l.34-.65c1.108-2.1 2.53-4.606 4.422-7.82z"/></g><path d="M57.963 76.556a1.512 1.512 0 0 1 2.027-.102l.108.098 17.27 17.198 24.354-7.42a1.51 1.51 0 0 1 1.835.866l.049.136a1.51 1.51 0 0 1-.869 1.834l-.137.049-25.22 7.683a1.51 1.51 0 0 1-1.394-.273l-.112-.101-17.91-17.836a1.506 1.506 0 0 1-.001-2.132z" fill="#4285F4" fill-rule="nonzero"/><g><path d="M73.735 27.798a.957.957 0 0 1-.899-1.087 9.21 9.21 0 0 1 9.562-7.95c4.828.22 8.699 4.061 9.082 8.793a.922.922 0 0 1-.96 1.004l-16.785-.76z" fill="#F882FF"/><path d="M46.537 44.15l-7.78 3.522c-1.1.499-1.249 1.981-.268 2.67l6.939 4.87c.98.69 2.354.068 2.473-1.118l.842-8.396c.12-1.187-1.107-2.047-2.206-1.549" fill="#D2E3FC"/><path d="M45.335 46.642c-2.101-2.484-1.676-6.184.948-8.262l11.107-8.82c2.625-2.08 6.456-1.752 8.557.732s1.677 6.184-.948 8.263l-11.106 8.82c-2.625 2.08-6.456 1.75-8.558-.733" fill="#FABD04"/><g transform="rotate(-102 42.988 6.811)"><mask id="d" fill="#fff"><use xlink:href="#c"/></mask><path d="M3.01-6.275c-.34 0-.687.118-.977.375L-4.024-.53c-.856.758-.57 2.16.514 2.523L4.162 4.56c.16.053.32.078.476.078.896 0 1.644-.83 1.45-1.785L4.472-5.084a1.484 1.484 0 0 0-1.461-1.19M2.817-4.19l1.398 6.865-6.638-2.22 5.24-4.645" fill="#FFF" mask="url(#d)"/></g><path d="M43.26 66.655l-3.847-6.7a2.573 2.573 0 0 0-2.228-1.28l-7.868-.026a2.63 2.63 0 0 0-2.261 1.264l-4.022 6.673a2.504 2.504 0 0 0-.032 2.543l3.847 6.7a2.572 2.572 0 0 0 2.228 1.28l7.868.026a2.632 2.632 0 0 0 2.262-1.264l4.02-6.672a2.503 2.503 0 0 0 .033-2.544" fill="#38A953"/><path d="M42.107 102.465h0v-.002a8.461 8.461 0 0 0-1.253-1.538l-1.343-1.65a6.942 6.942 0 0 1-1.515-5.197l.28-2.386.122-1.045-.055-.007a5.94 5.94 0 0 0-.06-.752c-.492-3.26-3.588-5.485-6.915-4.972-3.328.513-5.628 3.571-5.135 6.83.037.252.097.496.165.735l-.05.024.424.96.97 2.194a6.96 6.96 0 0 1 .088 5.417l-.795 1.98a8.491 8.491 0 0 0-.741 1.845l-.001.002h0a8.374 8.374 0 0 0-.038 4.236c1.006 4.032 4.942 6.764 9.169 6.373 5.048-.468 8.615-4.991 7.886-9.824a8.323 8.323 0 0 0-1.203-3.223z" stroke="#D2E3FC" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/><path d="M40.532 135.356c-7.25-.375-12.761-6.448-12.311-13.564l.013-.21c.449-7.116 6.69-12.581 13.939-12.206 7.25.375 12.761 6.448 12.311 13.564l-.013.21c-.45 7.117-6.69 12.581-13.939 12.206" fill="#EA4335"/><g transform="rotate(-103 70.313 56.882)"><mask id="f" fill="#fff"><use xlink:href="#e"/></mask><path d="M28.924.89c-4.53.083-8.37 3.754-8.984 8.531-.727 5.66 3.137 10.797 8.463 11.23a8.667 8.667 0 0 0 3.378-.392l.274-.097.373-.145c.485-.2.925-.425 1.339-.683l.258-.17 1.826-.942a5.58 5.58 0 0 1 4.559-.274l3.188 1.201.11.034c.11.026.223.031.331.016l.02-.004.258.04c.092.013.183.022.275.03 3.737.304 6.968-2.686 7.245-6.64.278-3.947-2.488-7.413-6.216-7.717l-.31-.016h-.227l-.028-.01a.899.899 0 0 0-.324-.035l-.156.024-3.276.663-.275.048c-1.467.221-2.962-.153-4.2-1.061l-1.68-1.235-.225-.203a9.26 9.26 0 0 0-1.183-.869l-.317-.186A8.772 8.772 0 0 0 29.265.889h-.341zm.35 1.81a6.957 6.957 0 0 1 2.96.745l.296.157c.515.29.993.642 1.427 1.049l.083.068 1.714 1.26c1.723 1.265 3.848 1.744 5.905 1.328l3.01-.61.078.011.055.002.056-.001a4.46 4.46 0 0 1 .615.002c2.71.22 4.77 2.8 4.56 5.787-.21 2.979-2.592 5.184-5.294 4.964a4.622 4.622 0 0 1-.611-.097l-.111-.017-.079-.003-2.89-1.09a7.39 7.39 0 0 0-6.029.36l-1.87.968-.095.056a7.217 7.217 0 0 1-1.55.802l-.298.103a6.838 6.838 0 0 1-2.657.304c-4.266-.347-7.413-4.532-6.814-9.196.502-3.911 3.616-6.887 7.222-6.954l.316.001z" fill="#FFF" fill-rule="nonzero" mask="url(#f)"/></g></g><g><g transform="rotate(9 44.073 633.419)"><mask id="h" fill="#fff"><use xlink:href="#g"/></mask><path d="M35.644 27.522l-24.76 9.258a1.253 1.253 0 0 1-1.614-.745L.079 11.095a1.268 1.268 0 0 1 .74-1.627L25.58.21c.65-.243 1.372.09 1.614.745l9.191 24.94a1.268 1.268 0 0 1-.74 1.627" fill="#4285F4" mask="url(#h)"/></g><path d="M121.048 11.073a4.033 4.033 0 0 0-1.246.577l-.217.161c-.247.196-.47.42-.664.668l-.548.544a2.164 2.164 0 0 1-1.531.64h-1.374l-.094.007a.686.686 0 0 0-.177.052l-.072.014-.12.03a3.055 3.055 0 0 0-2.149 3.73 3.024 3.024 0 0 0 3.71 2.157l.2-.064.06-.007a.65.65 0 0 0 .13-.042l.178-.099 1.076-.625a2.152 2.152 0 0 1 1.64-.217l.815.22c.218.091.522.173.835.22.667.097 1.35.027 2-.215 1.854-.691 2.95-2.67 2.562-4.618-.461-2.313-2.759-3.742-5.014-3.133zm3.732 3.388c.263 1.322-.485 2.672-1.737 3.139a2.723 2.723 0 0 1-1.965-.019l-.888-.244a3.459 3.459 0 0 0-2.636.35l-1.052.609-.072.024a1.717 1.717 0 0 1-2.31-1.157 1.748 1.748 0 0 1 1.224-2.136l.065-.016c.045-.01.094-.018.15-.025l.069-.016 1.215-.001a3.47 3.47 0 0 0 2.456-1.024l.598-.601.106-.127a3.04 3.04 0 0 1 .4-.388l.16-.117a2.734 2.734 0 0 1 4.217 1.749zm-21.012-1.449a3.139 3.139 0 0 0-2.443 3.69 3.11 3.11 0 0 0 3.669 2.451 3.139 3.139 0 0 0 2.442-3.689 3.111 3.111 0 0 0-3.668-2.452zm2.387 2.706a1.832 1.832 0 0 1-1.422 2.155 1.803 1.803 0 0 1-2.126-1.426 1.833 1.833 0 0 1 1.422-2.155 1.803 1.803 0 0 1 2.09 1.281l.036.145z" fill="#FFF" fill-rule="nonzero"/><g transform="rotate(9 43.883 633.603)"><mask id="j" fill="#fff"><use xlink:href="#i"/></mask><path d="M13.402 18.342a.654.654 0 0 1 .782-.355l.09.035 25.268 11.894a.653.653 0 0 1-.467 1.217l-.09-.035-24.67-11.613-6.724 14.77a.654.654 0 0 1-.775.357l-.09-.033a.653.653 0 0 1-.358-.775l.034-.09 7-15.372z" fill="#FFF" fill-rule="nonzero" mask="url(#j)"/></g></g></g>
+    </defs>
   </svg>
 </iron-iconset-svg>
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_shared_resources.grd b/chrome/browser/resources/nearby_share/shared/nearby_shared_resources.grd
new file mode 100644
index 0000000..553ab32
--- /dev/null
+++ b/chrome/browser/resources/nearby_share/shared/nearby_shared_resources.grd
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/nearby_shared_resources.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="grit/nearby_shared_resources_map.cc"
+            type="resource_file_map_source" />
+    <output filename="grit/nearby_shared_resources_map.h"
+            type="resource_map_header" />
+    <output filename="nearby_shared_resources.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <includes>
+      <!-- Shared Polymer 2 pages-->
+      <include name="IDR_NEARBY_CONTACT_VISIBILITY_HTML"
+               file="nearby_contact_visibility.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_CONTACT_VISIBILITY_JS"
+               file="nearby_contact_visibility.js" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_ONBOARDING_PAGE_HTML"
+               file="nearby_onboarding_page.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_ONBOARDING_PAGE_JS"
+               file="nearby_onboarding_page.js" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_HTML"
+               file="nearby_share_settings.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_JS"
+               file="nearby_share_settings.js" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_HTML"
+               file="nearby_share_settings_behavior.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_JS"
+               file="nearby_share_settings_behavior.js" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARED_ICONS_HTML"
+               file="nearby_shared_icons.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_VISIBILITY_PAGE_HTML"
+               file="nearby_visibility_page.html" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_VISIBILITY_PAGE_JS"
+               file="nearby_visibility_page.js" type="BINDATA" compress="false"/>
+    </includes>
+  </release>
+</grit>
diff --git a/chrome/browser/resources/nearby_share/shared/nearby_shared_resources_v3.grd b/chrome/browser/resources/nearby_share/shared/nearby_shared_resources_v3.grd
new file mode 100644
index 0000000..63301a8
--- /dev/null
+++ b/chrome/browser/resources/nearby_share/shared/nearby_shared_resources_v3.grd
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
+  <outputs>
+    <output filename="grit/nearby_shared_resources_v3.h" type="rc_header">
+      <emit emit_type='prepend'></emit>
+    </output>
+    <output filename="grit/nearby_shared_resources_v3_map.cc"
+            type="resource_file_map_source" />
+    <output filename="grit/nearby_shared_resources_v3_map.h"
+            type="resource_map_header" />
+    <output filename="nearby_shared_resources_v3.pak" type="data_package" />
+  </outputs>
+  <release seq="1">
+    <includes>
+      <!-- Generated Polymer 2 to 3 elements -->
+      <include name="IDR_NEARBY_CONTACT_VISIBILITY_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_contact_visibility.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_ONBOARDING_PAGE_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_onboarding_page.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_share_settings.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARE_SETTINGS_BEHAVIOR_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_share_settings_behavior.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_SHARED_ICONS_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_shared_icons.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+      <include name="IDR_NEARBY_VISIBILITY_PAGE_M_JS"
+               file="${root_gen_dir}/chrome/browser/resources/nearby_share/shared/nearby_visibility_page.m.js"
+               use_base_dir="false" type="BINDATA" compress="false"/>
+    </includes>
+  </release>
+</grit>
diff --git a/chrome/browser/resources/new_tab_page/BUILD.gn b/chrome/browser/resources/new_tab_page/BUILD.gn
index 5a69b32..c83b365 100644
--- a/chrome/browser/resources/new_tab_page/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/BUILD.gn
@@ -18,6 +18,9 @@
     ":fakebox",
     ":iframe",
     ":logo",
+    ":module_descriptor",
+    ":module_registry",
+    ":modules",
     ":one_google_bar_api",
     ":promo_browser_command_proxy",
     ":realbox",
@@ -28,9 +31,6 @@
     ":theme_icon",
     ":utils",
     ":voice_search_overlay",
-    "modules:module_descriptor",
-    "modules:module_registry",
-    "modules:modules",
   ]
 }
 
@@ -48,11 +48,11 @@
   deps = [
     ":background_manager",
     ":browser_proxy",
+    ":module_wrapper",
+    ":modules",
     ":most_visited",
     ":one_google_bar_api",
     ":promo_browser_command_proxy",
-    "modules:module_wrapper",
-    "modules:modules",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/js:event_tracker.m",
     "//ui/webui/resources/js:load_time_data.m",
@@ -221,6 +221,33 @@
 js_library("one_google_bar_api") {
 }
 
+js_library("module_descriptor") {
+  sources = [ "modules/module_descriptor.js" ]
+}
+
+js_library("modules") {
+  sources = [ "modules/modules.js" ]
+  deps = [
+    ":module_registry",
+    "modules/dummy:module",
+    "modules/kaleidoscope:module",
+  ]
+}
+
+js_library("module_wrapper") {
+  deps = [
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+}
+
+js_library("module_registry") {
+  sources = [ "modules/module_registry.js" ]
+  deps = [
+    ":module_descriptor",
+    "//ui/webui/resources/js:cr.m",
+  ]
+}
+
 html_to_js("web_components_local") {
   js_files = [
     "app.js",
@@ -241,13 +268,14 @@
     "theme_icon.js",
     "iframe.js",
     "voice_search_overlay.js",
+    "module_wrapper.js",
   ]
 }
 
 group("web_components") {
   public_deps = [
     ":web_components_local",
-    "modules:web_components",
+    "modules/dummy:web_components",
   ]
 }
 
diff --git a/chrome/browser/resources/new_tab_page/app.js b/chrome/browser/resources/new_tab_page/app.js
index 53c8228..e0f6989 100644
--- a/chrome/browser/resources/new_tab_page/app.js
+++ b/chrome/browser/resources/new_tab_page/app.js
@@ -10,7 +10,7 @@
 import './fakebox.js';
 import './realbox.js';
 import './logo.js';
-import './modules/module_wrapper.js';
+import './module_wrapper.js';
 import './modules/modules.js'; // Registers module descriptors.
 import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
 import 'chrome://resources/cr_elements/shared_style_css.m.js';
diff --git a/chrome/browser/resources/new_tab_page/modules/module_wrapper.html b/chrome/browser/resources/new_tab_page/module_wrapper.html
similarity index 100%
rename from chrome/browser/resources/new_tab_page/modules/module_wrapper.html
rename to chrome/browser/resources/new_tab_page/module_wrapper.html
diff --git a/chrome/browser/resources/new_tab_page/modules/module_wrapper.js b/chrome/browser/resources/new_tab_page/module_wrapper.js
similarity index 93%
rename from chrome/browser/resources/new_tab_page/modules/module_wrapper.js
rename to chrome/browser/resources/new_tab_page/module_wrapper.js
index c446285..1982f71 100644
--- a/chrome/browser/resources/new_tab_page/modules/module_wrapper.js
+++ b/chrome/browser/resources/new_tab_page/module_wrapper.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-import {ModuleDescriptor} from './module_descriptor.js';
+import {ModuleDescriptor} from './modules/module_descriptor.js';
 
 /** @fileoverview Element that implements the common module UI. */
 
diff --git a/chrome/browser/resources/new_tab_page/modules/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/BUILD.gn
deleted file mode 100644
index 3618ea2..0000000
--- a/chrome/browser/resources/new_tab_page/modules/BUILD.gn
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/polymer/html_to_js.gni")
-
-js_library("module_descriptor") {
-}
-
-js_library("modules") {
-  deps = [
-    ":module_registry",
-    "dummy:module",
-    "kaleidoscope:module",
-  ]
-}
-
-js_library("module_wrapper") {
-  deps = [
-    ":module_descriptor",
-    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-  ]
-}
-
-js_library("module_registry") {
-  deps = [
-    ":module_descriptor",
-    "//ui/webui/resources/js:cr.m",
-  ]
-}
-
-html_to_js("web_components_local") {
-  js_files = [ "module_wrapper.js" ]
-}
-
-group("web_components") {
-  public_deps = [
-    ":web_components_local",
-    "dummy:web_components",
-  ]
-}
diff --git a/chrome/browser/resources/new_tab_page/modules/dummy/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/dummy/BUILD.gn
index 0137665..b20d7fb 100644
--- a/chrome/browser/resources/new_tab_page/modules/dummy/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/dummy/BUILD.gn
@@ -7,7 +7,7 @@
 
 js_library("module") {
   deps = [
-    "..:module_descriptor",
+    "../..:module_descriptor",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/cr_elements/cr_grid",
   ]
diff --git a/chrome/browser/resources/new_tab_page/modules/kaleidoscope/BUILD.gn b/chrome/browser/resources/new_tab_page/modules/kaleidoscope/BUILD.gn
index abeb9aba..67fb3b3e 100644
--- a/chrome/browser/resources/new_tab_page/modules/kaleidoscope/BUILD.gn
+++ b/chrome/browser/resources/new_tab_page/modules/kaleidoscope/BUILD.gn
@@ -1,9 +1,5 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("module") {
-  deps = [ "..:module_descriptor" ]
+  deps = [ "//chrome/browser/resources/new_tab_page:module_descriptor" ]
 }
diff --git a/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp b/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
index d02a1174..67c4e16c 100644
--- a/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
+++ b/chrome/browser/resources/new_tab_page/modules/modules_resources.grdp
@@ -6,13 +6,4 @@
   <include name="IDR_NEW_TAB_PAGE_MODULES_KALEIDOSCOPE_MODULE_JS"
       file="modules/kaleidoscope/module.js"
       type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_MODULE_DESCRIPTOR_JS"
-      file="modules/module_descriptor.js" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_MODULES_JS"
-      file="modules/modules.js" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULES_MODULE_REGISTRY_JS"
-      file="modules/module_registry.js" type="BINDATA" compress="false" />
-  <include name="IDR_NEW_TAB_PAGE_MODULE_WRAPPER_JS"
-      file="${root_gen_dir}/chrome/browser/resources/new_tab_page/modules/module_wrapper.js"
-      use_base_dir="false" type="BINDATA" compress="false" />
 </grit-part>
diff --git a/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd b/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
index 6d754c3..871c434 100644
--- a/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
+++ b/chrome/browser/resources/new_tab_page/new_tab_page_resources.grd
@@ -69,12 +69,21 @@
       <include name="IDR_NEW_TAB_PAGE_REALBOX_MATCH_JS"
           file="${root_gen_dir}/chrome/browser/resources/new_tab_page/realbox_match.js"
           use_base_dir="false" type="BINDATA" compress="false" />
+      <include name="IDR_NEW_TAB_PAGE_MODULE_WRAPPER_JS"
+          file="${root_gen_dir}/chrome/browser/resources/new_tab_page/module_wrapper.js"
+          use_base_dir="false" type="BINDATA" compress="false" />
       <include name="IDR_NEW_TAB_PAGE_BROWSER_PROXY_JS"
           file="browser_proxy.js" type="BINDATA" compress="false" />
       <include name="IDR_NEW_TAB_PAGE_UTILS_JS"
           file="utils.js" type="BINDATA" compress="false" />
       <include name="IDR_NEW_TAB_PAGE_BACKGROUND_MANAGER_JS"
           file="background_manager.js" type="BINDATA" compress="false" />
+      <include name="IDR_NEW_TAB_PAGE_MODULES_MODULE_DESCRIPTOR_JS"
+          file="modules/module_descriptor.js" type="BINDATA" compress="false" />
+      <include name="IDR_NEW_TAB_PAGE_MODULES_MODULES_JS"
+          file="modules/modules.js" type="BINDATA" compress="false" />
+      <include name="IDR_NEW_TAB_PAGE_MODULES_MODULE_REGISTRY_JS"
+          file="modules/module_registry.js" type="BINDATA" compress="false" />
       <part file="new_tab_page_resources_common.grdp" />
       <part file="modules/modules_resources.grdp" />
     </includes>
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index c08dce7..f500e43 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -54,11 +54,13 @@
       "chrome://resources/mojo/skia/public/mojom/bitmap.mojom-lite.js",
       "chrome://resources/mojo/skia/public/mojom/image_info.mojom-lite.js",
       "chrome://resources/mojo/url/mojom/url.mojom-lite.js",
-      "shared/nearby_share_settings.html",
-      "shared/nearby_share_settings_behavior.html",
+      "mojo/nearby_share_settings.mojom-lite.js",
     ]
 
-    deps = [ ":unpak" ]
+    deps = [
+      ":unpak",
+      ":unpak_nearby",
+    ]
   }
 
   optimize_webui("build_polymer3") {
@@ -75,6 +77,7 @@
     ]
 
     deps = [
+      ":unpak_nearby_v3",
       ":unpak_v3",
       "../../../../../ui/webui/resources:modulize",
     ]
@@ -98,8 +101,7 @@
       "search/search.mojom-lite.js",
       "search/search_result_icon.mojom-lite.js",
       "search/user_action_recorder.mojom-lite.js",
-      "shared/nearby_share_settings.m.js",
-      "shared/nearby_share_settings_behavior.m.js",
+      "mojo/nearby_share_settings.mojom-lite.js",
     ]
   }
 
@@ -134,6 +136,30 @@
     deps = [ ":flattened_resources" ]
   }
 
+  unpak("unpak_nearby") {
+    pak_file = "../../../../nearby_shared_resources.pak"
+    out_folder = unpak_folder + "/shared"
+    pak_base_dir = "../../"
+    excludes = unpak_excludes
+
+    deps = [
+      ":unpak",
+      "//chrome/browser/resources:nearby_shared_resources",
+    ]
+  }
+
+  unpak("unpak_nearby_v3") {
+    pak_file = "../../../../nearby_shared_resources_v3.pak"
+    out_folder = unpak_folder_v3 + "/shared"
+    pak_base_dir = "../../nearby_share/shared/"
+    excludes = unpak_excludes
+
+    deps = [
+      ":unpak_v3",
+      "//chrome/browser/resources:nearby_shared_resources_v3",
+    ]
+  }
+
   grit("flattened_resources") {
     source = "../os_settings_resources.grd"
 
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn
index 1af112c6..a3216314 100644
--- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/BUILD.gn
@@ -32,7 +32,6 @@
   deps = [
     ":ambient_mode_browser_proxy",
     ":constants",
-    "..:deep_linking_behavior",
     "..:os_route",
     "../..:router",
     "../../prefs:prefs_behavior",
@@ -120,7 +119,6 @@
   deps = [
     ":ambient_mode_browser_proxy.m",
     ":constants.m",
-    "..:deep_linking_behavior.m",
     "..:os_route.m",
     "../..:router.m",
     "../../prefs:prefs_behavior.m",
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.html b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.html
index d21fc725..49a9d1f6 100644
--- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.html
+++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.html
@@ -8,7 +8,6 @@
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="constants.html">
 <link rel="import" href="topic_source_list.html">
-<link rel="import" href="../deep_linking_behavior.html">
 <link rel="import" href="../os_route.html">
 <link rel="import" href="../../router.html">
 <link rel="import" href="../../prefs/prefs.html">
@@ -62,8 +61,7 @@
         class="primary-toggle"
         pref="{{prefs.settings.ambient_mode.enabled}}"
         label="[[getAmbientModeOnOffLabel_(
-            prefs.settings.ambient_mode.enabled.value)]]"
-        deep-link-focus-id$="[[Setting.kAmbientModeOnOff]]">
+            prefs.settings.ambient_mode.enabled.value)]]">
     </settings-toggle-button>
 
     <template is="dom-if" if="[[prefs.settings.ambient_mode.enabled.value]]">
diff --git a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.js b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.js
index 898f743..12bef93 100644
--- a/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.js
+++ b/chrome/browser/resources/settings/chromeos/ambient_mode_page/ambient_mode_page.js
@@ -10,8 +10,8 @@
   is: 'settings-ambient-mode-page',
 
   behaviors: [
-    DeepLinkingBehavior, I18nBehavior, PrefsBehavior,
-    settings.RouteObserverBehavior, WebUIListenerBehavior
+    I18nBehavior, PrefsBehavior, settings.RouteObserverBehavior,
+    WebUIListenerBehavior
   ],
 
   properties: {
@@ -57,18 +57,6 @@
       value: AmbientModeTemperatureUnit.UNKNOWN,
       observer: 'onSelectedTemperatureUnitChanged_'
     },
-
-    /**
-     * Used by DeepLinkingBehavior to focus this page's deep links.
-     * @type {!Set<!chromeos.settings.mojom.Setting>}
-     */
-    supportedSettingIds: {
-      type: Object,
-      value: () => new Set([
-        chromeos.settings.mojom.Setting.kAmbientModeOnOff,
-        chromeos.settings.mojom.Setting.kAmbientModeSource,
-      ]),
-    },
   },
 
   listeners: {
@@ -101,33 +89,6 @@
   },
 
   /**
-   * Overridden from DeepLinkingBehavior.
-   * @param {!chromeos.settings.mojom.Setting} settingId
-   */
-  beforeDeepLinkAttempt(settingId) {
-    if (settingId !== chromeos.settings.mojom.Setting.kAmbientModeSource) {
-      // Continue with deep link attempt.
-      return true;
-    }
-
-    // Wait for element to load.
-    Polymer.RenderStatus.afterNextRender(this, () => {
-      Polymer.dom.flush();
-
-      const topicList = this.$$('topic-source-list');
-      const listItem = topicList && topicList.$$('topic-source-item');
-      if (listItem) {
-        this.showDeepLinkElement(listItem);
-        return;
-      }
-
-      console.warn(`Element with deep link id ${settingId} not focusable.`);
-    });
-    // Stop deep link attempt since we completed it manually.
-    return false;
-  },
-
-  /**
    * RouteObserverBehavior
    * @param {!settings.Route} currentRoute
    * @protected
@@ -138,7 +99,6 @@
     }
 
     this.browserProxy_.requestSettings();
-    this.attemptDeepLink();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.js b/chrome/browser/resources/settings/chromeos/os_settings.js
index 7939ed10..0b98f37 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.js
+++ b/chrome/browser/resources/settings/chromeos/os_settings.js
@@ -30,6 +30,8 @@
 export {PageStatus, StoredAccount, SyncBrowserProxy, SyncBrowserProxyImpl, SyncStatus} from '../people_page/sync_browser_proxy.m.js';
 export {CrSettingsPrefs} from '../prefs/prefs_types.m.js';
 export {Route, Router} from '../router.m.js';
+export {getNearbyShareSettings, observeNearbyShareSettings, setNearbyShareSettingsForTesting} from '../shared/nearby_share_settings.m.js';
+export {NearbySettings, NearbyShareSettingsBehavior} from '../shared/nearby_share_settings_behavior.m.js';
 export {AmbientModeBrowserProxyImpl} from './ambient_mode_page/ambient_mode_browser_proxy.m.js';
 export {AmbientModeTemperatureUnit, AmbientModeTopicSource} from './ambient_mode_page/constants.m.js';
 export {bluetoothApis} from './bluetooth_page/bluetooth_page.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
index aaf988a..93bd224 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
+++ b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
@@ -648,6 +648,11 @@
            use_base_dir="false"
            compress="false"
            type="BINDATA" />
+  <include name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_M_JS"
+           file="${root_gen_dir}/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.m.js"
+           use_base_dir="false"
+           compress="false"
+           type="BINDATA" />
   <include name="IDR_OS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_M_JS"
            file="${root_gen_dir}/chrome/browser/resources/settings/nearby_share_page/nearby_share_device_name_dialog.m.js"
            use_base_dir="false"
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
index 8e3b695fd..dddafc3 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/BUILD.gn
@@ -18,7 +18,6 @@
 js_library("change_picture") {
   deps = [
     ":change_picture_browser_proxy",
-    "..:deep_linking_behavior",
     "..:metrics_recorder",
     "..:os_route",
     "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
@@ -41,7 +40,6 @@
 js_library("personalization_page") {
   deps = [
     ":wallpaper_browser_proxy",
-    "..:deep_linking_behavior",
     "..:os_route",
     "../..:router",
     "../../prefs",
@@ -70,7 +68,6 @@
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.m.js" ]
   deps = [
     ":change_picture_browser_proxy.m",
-    "..:deep_linking_behavior.m",
     "..:metrics_recorder.m",
     "..:os_route.m",
     "../..:router.m",
@@ -99,7 +96,6 @@
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.m.js" ]
   deps = [
     ":wallpaper_browser_proxy.m",
-    "..:deep_linking_behavior.m",
     "..:os_route.m",
     "../..:router.m",
     "../../prefs:prefs.m",
@@ -133,7 +129,7 @@
   namespace_rewrites = os_settings_namespace_rewrites +
                        [ "Polymer.IronA11yAnnouncer|IronA11yAnnouncer" ]
   auto_imports = os_settings_auto_imports + [
-                   "ui/webui/resources/html/assert.html|assert,assertNotReached",
+                   "ui/webui/resources/html/assert.html|assertNotReached",
                    "ui/webui/resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.html|IronA11yAnnouncer",
                  ]
 }
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
index e82d07a..5f18549 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.html
@@ -9,7 +9,6 @@
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="../../i18n_setup.html">
-<link rel="import" href="../deep_linking_behavior.html">
 <link rel="import" href="../os_route.html">
 <link rel="import" href="../../router.html">
 <link rel="import" href="../../settings_shared_css.html">
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
index b6d63f5..3fd0f2d 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/change_picture.js
@@ -11,7 +11,6 @@
   is: 'settings-change-picture',
 
   behaviors: [
-    DeepLinkingBehavior,
     settings.RouteObserverBehavior,
     I18nBehavior,
     WebUIListenerBehavior,
@@ -67,16 +66,6 @@
 
     /** @private */
     oldImageLabel_: String,
-
-    /**
-     * Used by DeepLinkingBehavior to focus this page's deep links.
-     * @type {!Set<!chromeos.settings.mojom.Setting>}
-     */
-    supportedSettingIds: {
-      type: Object,
-      value: () =>
-          new Set([chromeos.settings.mojom.Setting.kChangeDeviceAccountImage]),
-    },
   },
 
   listeners: {
@@ -120,20 +109,6 @@
     Polymer.IronA11yAnnouncer.requestAvailability();
   },
 
-  /**
-   * Overridden from DeepLinkingBehavior.
-   * @param {!chromeos.settings.mojom.Setting} settingId
-   * @return {boolean}
-   */
-  beforeDeepLinkAttempt(settingId) {
-    assert(
-        settingId ===
-        chromeos.settings.mojom.Setting.kChangeDeviceAccountImage);
-
-    this.pictureList_.setFocus();
-    return false;
-  },
-
 
   /** @protected */
   currentRouteChanged(newRoute) {
@@ -141,7 +116,6 @@
       this.browserProxy_.initialize();
       this.browserProxy_.requestSelectedImage();
       this.pictureList_.setFocus();
-      this.attemptDeepLink();
     } else {
       // Ensure we deactivate the camera when we navigate away.
       this.selectedItem_ = null;
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
index 65a24021..1597b4c9 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.html
@@ -5,7 +5,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="change_picture.html">
-<link rel="import" href="../deep_linking_behavior.html">
 <link rel="import" href="../os_route.html">
 <link rel="import" href="../../router.html">
 <link rel="import" href="../../i18n_setup.html">
@@ -29,8 +28,7 @@
             hidden="[[!showWallpaperRow_]]"
             on-click="openWallpaperManager_" label="$i18n{setWallpaper}"
             sub-label="$i18n{openWallpaperApp}"
-            disabled="[[isWallpaperPolicyControlled_]]" external
-            deep-link-focus-id$="[[Setting.kOpenWallpaper]]">
+            disabled="[[isWallpaperPolicyControlled_]]" external>
           <template is="dom-if" if="[[isWallpaperPolicyControlled_]]">
             <cr-policy-indicator id="wallpaperPolicyIndicator"
                 indicator-type="devicePolicy">
diff --git a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
index 42288a50..da8c0b1 100644
--- a/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
+++ b/chrome/browser/resources/settings/chromeos/personalization_page/personalization_page.js
@@ -9,11 +9,7 @@
 Polymer({
   is: 'settings-personalization-page',
 
-  behaviors: [
-    DeepLinkingBehavior,
-    I18nBehavior,
-    settings.RouteObserverBehavior,
-  ],
+  behaviors: [I18nBehavior],
 
   properties: {
     /**
@@ -50,15 +46,6 @@
         return map;
       }
     },
-
-    /**
-     * Used by DeepLinkingBehavior to focus this page's deep links.
-     * @type {!Set<!chromeos.settings.mojom.Setting>}
-     */
-    supportedSettingIds: {
-      type: Object,
-      value: () => new Set([chromeos.settings.mojom.Setting.kOpenWallpaper]),
-    },
   },
 
   /** @private {?settings.WallpaperBrowserProxy} */
@@ -82,19 +69,6 @@
   },
 
   /**
-   * @param {!settings.Route} route
-   * @param {!settings.Route} oldRoute
-   */
-  currentRouteChanged(route, oldRoute) {
-    // Does not apply to this page.
-    if (route !== settings.routes.PERSONALIZATION) {
-      return;
-    }
-
-    this.attemptDeepLink();
-  },
-
-  /**
    * @private
    */
   openWallpaperManager_() {
diff --git a/chrome/browser/resources/settings/nearby_share_page/BUILD.gn b/chrome/browser/resources/settings/nearby_share_page/BUILD.gn
index 1a52410d..56e0fea 100644
--- a/chrome/browser/resources/settings/nearby_share_page/BUILD.gn
+++ b/chrome/browser/resources/settings/nearby_share_page/BUILD.gn
@@ -5,10 +5,12 @@
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/polymer.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
+import("../../nearby_share/shared/nearby_shared.gni")
 import("../settings.gni")
 
 js_type_check("closure_compile") {
   deps = [
+    ":nearby_share_contact_visibility_dialog",
     ":nearby_share_data_usage_dialog",
     ":nearby_share_device_name_dialog",
     ":nearby_share_subpage",
@@ -16,6 +18,15 @@
   ]
 }
 
+js_library("nearby_share_contact_visibility_dialog") {
+  deps = [
+    "//chrome/browser/resources/nearby_share/shared:nearby_contact_visibility",
+    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings_behavior",
+    "//ui/webui/resources/cr_elements/cr_button:cr_button",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
+  ]
+}
+
 js_library("nearby_share_data_usage_dialog") {
   deps = [
     ":types",
@@ -44,6 +55,7 @@
 
 js_library("nearby_share_subpage") {
   deps = [
+    ":nearby_share_contact_visibility_dialog",
     ":nearby_share_data_usage_dialog",
     ":nearby_share_device_name_dialog",
     ":types",
@@ -51,7 +63,9 @@
     "../prefs",
     "../prefs:prefs_behavior",
     "../prefs:prefs_types",
-    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings",
+    "//chrome/browser/resources/nearby_share/shared:nearby_onboarding_page",
+    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings_behavior",
+    "//chrome/browser/resources/nearby_share/shared:nearby_visibility_page",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:i18n_behavior",
   ]
@@ -63,6 +77,7 @@
 group("polymer3_elements") {
   public_deps = [
     ":modulize",
+    ":nearby_share_contact_visibility_dialog_module",
     ":nearby_share_data_usage_dialog_module",
     ":nearby_share_device_name_dialog_module",
     ":nearby_share_subpage_module",
@@ -73,13 +88,30 @@
 
 js_type_check("closure_compile_module") {
   is_polymer3 = true
+
+  # TODO(crbug.com/1121865): browser_resolver_prefix_replacements allows path
+  # from ../shared/* to resolve to ../../nearby_share/shared/* for closure
+  # purposes.
+  closure_flags = default_closure_args + [ "browser_resolver_prefix_replacements=\"../shared/=../../nearby_share/shared/\"" ]
   deps = [
+    ":nearby_share_contact_visibility_dialog.m",
     ":nearby_share_data_usage_dialog.m",
     ":nearby_share_device_name_dialog.m",
     ":nearby_share_subpage.m",
   ]
 }
 
+js_library("nearby_share_contact_visibility_dialog.m") {
+  sources = [ "$root_gen_dir/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.m.js" ]
+  deps = [
+    "//chrome/browser/resources/nearby_share/shared:nearby_contact_visibility.m",
+    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings_behavior.m",
+    "//ui/webui/resources/cr_elements/cr_button:cr_button.m",
+    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+  ]
+  extra_deps = [ ":nearby_share_contact_visibility_dialog_module" ]
+}
+
 js_library("nearby_share_data_usage_dialog.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/nearby_share_page/nearby_share_data_usage_dialog.m.js" ]
   deps = [
@@ -113,6 +145,7 @@
 js_library("nearby_share_subpage.m") {
   sources = [ "$root_gen_dir/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.m.js" ]
   deps = [
+    ":nearby_share_contact_visibility_dialog.m",
     ":nearby_share_data_usage_dialog.m",
     ":nearby_share_device_name_dialog.m",
     ":types.m",
@@ -120,7 +153,9 @@
     "../prefs:prefs.m",
     "../prefs:prefs_behavior.m",
     "../prefs:prefs_types.m",
-    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings.m",
+    "//chrome/browser/resources/nearby_share/shared:nearby_onboarding_page.m",
+    "//chrome/browser/resources/nearby_share/shared:nearby_share_settings_behavior.m",
+    "//chrome/browser/resources/nearby_share/shared:nearby_visibility_page.m",
     "//ui/webui/resources/js:cr.m",
     "//ui/webui/resources/js:i18n_behavior.m",
   ]
@@ -137,6 +172,27 @@
   namespace_rewrites = settings_namespace_rewrites
 }
 
+nearby_shared_auto_imports_closure_fix = [
+  # TODO(crbug.com/1121865): polymer.py normalizes the relative paths to shared
+  # nearby resources like ../shared/* against c/b/r/settings/nearby_share_page
+  # genreating paths with the prefix c/b/r/settings/shared/*. It uses the
+  # normalized path to look up relative references for auto import. In order get
+  # the auto import to match, we need to use this path prefix even though it
+  # does not exist on disk there. The actual resources are in
+  # c/b/r/nearby_share/shared and are re-hosted in the chrome://os-settings
+  # webui at the chrome://os-settings/shared/* prefix.
+  "chrome/browser/resources/settings/shared/nearby_share_settings_behavior.html|NearbyShareSettingsBehavior,NearbySettings",
+]
+
+polymer_modulizer("nearby_share_contact_visibility_dialog") {
+  js_file = "nearby_share_contact_visibility_dialog.js"
+  html_file = "nearby_share_contact_visibility_dialog.html"
+  html_type = "dom-module"
+  namespace_rewrites =
+      settings_namespace_rewrites + nearby_shared_namespace_rewrites
+  auto_imports = settings_auto_imports + nearby_shared_auto_imports_closure_fix
+}
+
 polymer_modulizer("nearby_share_data_usage_dialog") {
   js_file = "nearby_share_data_usage_dialog.js"
   html_file = "nearby_share_data_usage_dialog.html"
@@ -157,8 +213,9 @@
   js_file = "nearby_share_subpage.js"
   html_file = "nearby_share_subpage.html"
   html_type = "dom-module"
-  namespace_rewrites = settings_namespace_rewrites
+  namespace_rewrites =
+      settings_namespace_rewrites + nearby_shared_namespace_rewrites
   auto_imports =
-      settings_auto_imports +
+      settings_auto_imports + nearby_shared_auto_imports_closure_fix +
       [ "chrome/browser/resources/settings/chromeos/os_route.html|routes" ]
 }
diff --git a/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.html b/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.html
new file mode 100644
index 0000000..bb8d0c2
--- /dev/null
+++ b/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.html
@@ -0,0 +1,32 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="../shared/nearby_contact_visibility.html">
+<link rel="import" href="../shared/nearby_onboarding_page.html">
+<link rel="import" href="../shared/nearby_share_settings_behavior.html">
+<link rel="import" href="../shared/nearby_visibility_page.html">
+
+<!-- TODO(vecore): The two imports above for onboarding and visibility pages are
+         temporary. They are need to ensure the pages are included in the
+         bundling until they are actually referenced by a settings hosted
+         onboarding flow.
+-->
+
+<dom-module id="nearby-share-contact-visibility-dialog">
+  <template>
+    <cr-dialog id="dialog" show-on-attach>
+      <div slot="title">$i18n{nearbyShareVisibilityDialogTitle}</div>
+      <div slot="body">
+        <nearby-contact-visibility settings="{{settings}}">
+        </nearby-contact-visibility>
+      </div>
+      <div class="layout horizontal center" slot="button-container">
+        <cr-button class="action-button" on-click="onDoneClick_">
+          $i18n{done}
+        </cr-button>
+      </div>
+    </cr-dialog>
+  </template>
+  <script src="nearby_share_contact_visibility_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.js b/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.js
new file mode 100644
index 0000000..b8575463
--- /dev/null
+++ b/chrome/browser/resources/settings/nearby_share_page/nearby_share_contact_visibility_dialog.js
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'nearby-share-contact-visibility-dialog' allows editing of the users contact
+ * visibility settings.
+ */
+Polymer({
+  is: 'nearby-share-contact-visibility-dialog',
+
+  properties: {
+    /** @type {nearby_share.NearbySettings} */
+    settings: {
+      type: Object,
+      value: {},
+    },
+  },
+
+  /** @private */
+  onDoneClick_() {
+    const dialog = /** @type {!CrDialogElement} */ (this.$.dialog);
+    if (dialog.open) {
+      dialog.close();
+    }
+  },
+});
diff --git a/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.html b/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.html
index 25be3c6..45f6728 100644
--- a/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.html
+++ b/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.html
@@ -2,13 +2,14 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="../shared/nearby_share_settings.html">
 <link rel="import" href="../chromeos/os_route.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../prefs/prefs_behavior.html">
 <link rel="import" href="../router.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="../shared/nearby_share_settings_behavior.html">
+<link rel="import" href="nearby_share_contact_visibility_dialog.html">
 <link rel="import" href="nearby_share_device_name_dialog.html">
 <link rel="import" href="nearby_share_data_usage_dialog.html">
 <link rel="import" href="types.html">
@@ -49,6 +50,25 @@
     </template>
     <div class="settings-box two-line">
       <div class="start">
+        <div role="heading" aria-hidden="true">
+          $i18n{nearbyShareContactVisibilityRowTitle}
+        </div>
+        <div aria-hidden="true" class="secondary">
+          [[getVisibilityText_(settings.visibility)]]
+        </div>
+      </div>
+      <cr-button id="editVisibilityButton" on-click="onVisibilityTap_"
+          aria-description="[[getVisibilityDescription_(settings.visibility)]]">
+        $i18n{nearbyShareEditVisibility}
+      </cr-button>
+    </div>
+    <template is="dom-if" if="[[showVisibilityDialog_]]" restamp>
+      <nearby-share-contact-visibility-dialog settings="{{settings}}"
+          id="visibilityDialog" on-close="onVisibilityDialogClose_">
+      </nearby-share-contact-visibility-dialog>
+    </template>
+    <div class="settings-box two-line">
+      <div class="start">
         <div aria-hidden="true">
           [[getDataUsageLabel_(prefs.nearby_sharing.data_usage.value)]]
         </div>
diff --git a/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.js b/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.js
index d8b8e6ab8..1b82afb 100644
--- a/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.js
+++ b/chrome/browser/resources/settings/nearby_share_page/nearby_share_subpage.js
@@ -14,6 +14,7 @@
     I18nBehavior,
     PrefsBehavior,
     settings.RouteObserverBehavior,
+    nearby_share.NearbyShareSettingsBehavior,
   ],
 
   properties: {
@@ -30,6 +31,12 @@
     },
 
     /** @private {boolean} */
+    showVisibilityDialog_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private {boolean} */
     showDataUsageDialog_: {
       type: Boolean,
       value: false,
@@ -56,6 +63,11 @@
   },
 
   /** @private */
+  onVisibilityTap_() {
+    this.showVisibilityDialog_ = true;
+  },
+
+  /** @private */
   onDataUsageTap_() {
     this.showDataUsageDialog_ = true;
   },
@@ -72,6 +84,14 @@
    * @param {!Event} event
    * @private
    */
+  onVisibilityDialogClose_(event) {
+    this.showVisibilityDialog_ = false;
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
   onDataUsageDialogClose_(event) {
     this.showDataUsageDialog_ = false;
   },
@@ -97,6 +117,46 @@
   },
 
   /**
+   * @param {nearbyShare.mojom.Visibility} visibility
+   * @return {string} localized visibility string
+   * @private
+   */
+  getVisibilityText_(visibility) {
+    switch (visibility) {
+      case nearbyShare.mojom.Visibility.kAllContacts:
+        return this.i18n('visibilityAllContacts');
+      case nearbyShare.mojom.Visibility.kSelectedContacts:
+        return this.i18n('visibilitySomeContacts');
+      case nearbyShare.mojom.Visibility.kNoOne:
+        return this.i18n('visibilityHidden');
+      case nearbyShare.mojom.Visibility.kUnknown:
+        return this.i18n('visibilityUnknown');
+      default:
+        return '';  // Make closure happy.
+    }
+  },
+
+  /**
+   * @param {nearbyShare.mojom.Visibility} visibility
+   * @return {string} localized visibility description string
+   * @private
+   */
+  getVisibilityDescription_(visibility) {
+    switch (visibility) {
+      case nearbyShare.mojom.Visibility.kAllContacts:
+        return this.i18n('visibilityAllContactsDescription');
+      case nearbyShare.mojom.Visibility.kSelectedContacts:
+        return this.i18n('visibilitySomeContactsDescription');
+      case nearbyShare.mojom.Visibility.kNoOne:
+        return this.i18n('visibilityHiddenDescription');
+      case nearbyShare.mojom.Visibility.kUnknown:
+        return this.i18n('visibilityUnknownDescription');
+      default:
+        return '';  // Make closure happy.
+    }
+  },
+
+  /**
    * @param {string} dataUsageValue enum value of data usage setting.
    * @return {string} localized string
    * @private
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd
index 8462938..3e2f2dd 100644
--- a/chrome/browser/resources/settings/os_settings_resources.grd
+++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -1310,6 +1310,12 @@
       <structure name="IDR_OS_SETTINGS_MULTIDEVICE_TETHER_ITEM_JS"
                  file="chromeos/multidevice_page/multidevice_tether_item.js"
                  compress="false" type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_HTML"
+                 file="nearby_share_page/nearby_share_contact_visibility_dialog.html"
+                 compress="false" type="chrome_html" />
+      <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_DIALOG_JS"
+                 file="nearby_share_page/nearby_share_contact_visibility_dialog.js"
+                 compress="false" type="chrome_html" />
       <structure name="IDR_OS_SETTINGS_NEARBY_SHARE_DEVICE_NAME_DIALOG_HTML"
                  file="nearby_share_page/nearby_share_device_name_dialog.html"
                  compress="false" type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragment.java b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragment.java
index c95f7816..f7ac281 100644
--- a/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragment.java
+++ b/chrome/browser/safe_browsing/android/java/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragment.java
@@ -40,8 +40,7 @@
     protected void onCreatePreferencesInternal(Bundle bundle, String rootKey) {
         mExtendedReportingPreference = findPreference(PREF_EXTENDED_REPORTING);
         mExtendedReportingPreference.setOnPreferenceChangeListener(this);
-        // TODO(crbug.com/1108604): Set ManagedPreferenceDelegate for mExtendedReportingPreference
-        // when the extended reporting policy is supported on Android.
+        mExtendedReportingPreference.setManagedPreferenceDelegate(mManagedPreferenceDelegate);
 
         mPasswordLeakDetectionPreference = findPreference(PREF_PASSWORD_LEAK_DETECTION);
         mPasswordLeakDetectionPreference.setOnPreferenceChangeListener(this);
@@ -73,7 +72,11 @@
         boolean extended_reporting_checked = is_enhanced_protection
                 || (is_standard_protection
                         && SafeBrowsingBridge.isSafeBrowsingExtendedReportingEnabled());
-        mExtendedReportingPreference.setEnabled(is_standard_protection);
+        boolean extended_reporting_disabled_by_delegate =
+                mManagedPreferenceDelegate.isPreferenceClickDisabledByPolicy(
+                        mExtendedReportingPreference);
+        mExtendedReportingPreference.setEnabled(
+                is_standard_protection && !extended_reporting_disabled_by_delegate);
         mExtendedReportingPreference.setChecked(extended_reporting_checked);
 
         boolean has_token_for_leak_check = SafeBrowsingBridge.hasAccountForLeakCheckRequest();
@@ -114,7 +117,9 @@
     private ChromeManagedPreferenceDelegate createManagedPreferenceDelegate() {
         return preference -> {
             String key = preference.getKey();
-            if (PREF_PASSWORD_LEAK_DETECTION.equals(key)) {
+            if (PREF_EXTENDED_REPORTING.equals(key)) {
+                return SafeBrowsingBridge.isSafeBrowsingExtendedReportingManaged();
+            } else if (PREF_PASSWORD_LEAK_DETECTION.equals(key)) {
                 return mPrefService.isManagedPreference(Pref.PASSWORD_LEAK_DETECTION_ENABLED);
             } else {
                 assert false : "Should not be reached";
diff --git a/chrome/browser/safe_browsing/android/javatests/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragmentTest.java b/chrome/browser/safe_browsing/android/javatests/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragmentTest.java
index 0c2a726..8640841a 100644
--- a/chrome/browser/safe_browsing/android/javatests/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragmentTest.java
+++ b/chrome/browser/safe_browsing/android/javatests/src/org/chromium/chrome/browser/safe_browsing/settings/StandardProtectionSettingsFragmentTest.java
@@ -243,6 +243,29 @@
         });
     }
 
+    @Test
+    @SmallTest
+    @Feature({"SafeBrowsing"})
+    @Policies.Add({ @Policies.Item(key = "SafeBrowsingExtendedReportingEnabled", string = "true") })
+    public void testExtendedReportingPolicyManaged() {
+        mBrowserTestRule.addAndSignInTestAccount();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            ChromeBrowserInitializer.getInstance().handleSynchronousStartup();
+            SafeBrowsingBridge.setSafeBrowsingState(SafeBrowsingState.STANDARD_PROTECTION);
+        });
+        launchSettingsActivity();
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            Assert.assertTrue(
+                    ASSERT_MESSAGE_PREFIX + EXTENDED_REPORTING + MANAGED_STATE + FROM_NATIVE,
+                    SafeBrowsingBridge.isSafeBrowsingExtendedReportingManaged());
+            Assert.assertFalse(ASSERT_MESSAGE_PREFIX + EXTENDED_REPORTING + ENABLED_STATE,
+                    mExtendedReportingPreference.isEnabled());
+            Assert.assertTrue(ASSERT_MESSAGE_PREFIX + EXTENDED_REPORTING + CHECKED_STATE,
+                    mExtendedReportingPreference.isChecked());
+        });
+    }
+
     PrefService getPrefService() {
         return UserPrefs.get(Profile.getLastUsedRegularProfile());
     }
diff --git a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
index 8c8ad6af..1da9804 100644
--- a/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
+++ b/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <list>
 #include <memory>
 #include <utility>
 #include <vector>
@@ -77,6 +78,13 @@
         &profile_, base::BindRepeating(&BuildSpellcheckService));
   }
 
+  void TearDown() override {
+    // Allow tasks with pending I/O (e.g.,
+    // SpellcheckCustomDictionary::LoadDictionaryFile) to complete before
+    // destroying the testing profiles.
+    task_environment_.RunUntilIdle();
+  }
+
   // A wrapper around SpellcheckCustomDictionary::LoadDictionaryFile private
   // function to avoid a large number of FRIEND_TEST declarations in
   // SpellcheckCustomDictionary.
@@ -115,9 +123,20 @@
     return dictionary.Apply(change);
   }
 
+  // Returns the custom dictionary for an extra profile, created on demand.
+  SpellcheckCustomDictionary* MakeExtraProfileDictionary() {
+    extra_profiles_.emplace_back();
+    auto* const extra_profile = &extra_profiles_.back();
+    return static_cast<SpellcheckService*>(
+               SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+                   extra_profile, base::BindRepeating(&BuildSpellcheckService)))
+        ->GetCustomDictionary();
+  }
+
   content::BrowserTaskEnvironment task_environment_;
 
   TestingProfile profile_;
+  std::list<TestingProfile> extra_profiles_;
 };
 
 // An implementation of SyncErrorFactory that does not upload the error message
@@ -199,12 +218,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   std::set<std::string> expected1;
   std::set<std::string> expected2;
@@ -436,12 +450,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords / 2; ++i) {
@@ -498,12 +507,7 @@
   SpellcheckCustomDictionary* custom_dictionary =
       SpellcheckServiceFactory::GetForContext(&profile_)->GetCustomDictionary();
 
-  TestingProfile profile2;
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      static_cast<SpellcheckService*>(
-          SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              &profile2, base::BindRepeating(&BuildSpellcheckService)))
-          ->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   std::unique_ptr<SpellcheckCustomDictionary::Change> change(
       new SpellcheckCustomDictionary::Change);
@@ -550,12 +554,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords + 1; ++i) {
@@ -596,12 +595,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   SpellcheckCustomDictionary::Change change2;
@@ -651,12 +645,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   SpellcheckCustomDictionary::Change change2;
@@ -704,12 +693,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords - 1; ++i) {
@@ -753,12 +737,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords - 1; ++i) {
@@ -807,12 +786,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   custom_dictionary->AddWord("foo");
 
@@ -853,12 +827,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   custom_dictionary->AddWord("foo");
 
@@ -904,12 +873,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   SpellcheckCustomDictionary::Change change;
   for (size_t i = 0; i < spellcheck::kMaxSyncableDictionaryWords / 2; ++i) {
@@ -1020,12 +984,7 @@
       SpellcheckServiceFactory::GetForContext(&profile_);
   SpellcheckCustomDictionary* custom_dictionary =
       spellcheck_service->GetCustomDictionary();
-  TestingProfile profile2;
-  SpellcheckService* spellcheck_service2 = static_cast<SpellcheckService*>(
-      SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-          &profile2, base::BindRepeating(&BuildSpellcheckService)));
-  SpellcheckCustomDictionary* custom_dictionary2 =
-      spellcheck_service2->GetCustomDictionary();
+  SpellcheckCustomDictionary* custom_dictionary2 = MakeExtraProfileDictionary();
 
   OnLoaded(*custom_dictionary, base::WrapUnique(new std::set<std::string>));
   OnLoaded(*custom_dictionary2, base::WrapUnique(new std::set<std::string>));
@@ -1068,15 +1027,9 @@
 // sync server upon association. The client should accept words from the sync
 // server, however.
 TEST_F(SpellcheckCustomDictionaryTest, DictionarySyncLimit) {
-  TestingProfile server_profile;
-  SpellcheckService* server_spellcheck_service =
-      static_cast<SpellcheckService*>(
-          SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-              &server_profile, base::BindRepeating(&BuildSpellcheckService)));
-
   // Here, |server_custom_dictionary| plays the role of the sync server.
   SpellcheckCustomDictionary* server_custom_dictionary =
-      server_spellcheck_service->GetCustomDictionary();
+      MakeExtraProfileDictionary();
 
   // Upload the maximum number of words to the sync server.
   {
@@ -1117,15 +1070,9 @@
   // words, but all of these words are different from the ones on the sync
   // server.
   {
-    TestingProfile client_profile;
-    SpellcheckService* client_spellcheck_service =
-        static_cast<SpellcheckService*>(
-            SpellcheckServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-                &client_profile, base::BindRepeating(&BuildSpellcheckService)));
-
     // Here, |client_custom_dictionary| plays the role of the client.
     SpellcheckCustomDictionary* client_custom_dictionary =
-        client_spellcheck_service->GetCustomDictionary();
+        MakeExtraProfileDictionary();
 
     // Add the maximum number of words to the client. These words are all
     // different from those on the server.
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
index 661bd55..89f4b92 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/CriticalPersistedTabData.java
@@ -15,6 +15,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
+import org.chromium.base.TraceEvent;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tab.WebContentsState;
@@ -207,7 +208,7 @@
 
     @Override
     boolean deserialize(@Nullable byte[] bytes) {
-        try {
+        try (TraceEvent e = TraceEvent.scoped("CriticalPersistedTabData.Deserialize")) {
             CriticalPersistedTabDataProto criticalPersistedTabDataProto =
                     CriticalPersistedTabDataProto.parseFrom(bytes);
             mParentId = criticalPersistedTabDataProto.getParentId();
@@ -354,24 +355,26 @@
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
     @Override
     public byte[] serialize() {
-        WebContentsState webContentsState = mWebContentsState;
-        if (webContentsState == null) {
-            webContentsState = getWebContentsStateFromTab(mTab);
+        try (TraceEvent e = TraceEvent.scoped("CriticalPersistedTabData.Serialize")) {
+            WebContentsState webContentsState = mWebContentsState;
+            if (webContentsState == null) {
+                webContentsState = getWebContentsStateFromTab(mTab);
+            }
+            return CriticalPersistedTabDataProto.newBuilder()
+                    .setParentId(mParentId)
+                    .setRootId(mRootId)
+                    .setTimestampMillis(mTimestampMillis)
+                    .setWebContentsStateBytes(webContentsState == null
+                                    ? ByteString.EMPTY
+                                    : ByteString.copyFrom(
+                                            getContentStateByteArray(webContentsState.buffer())))
+                    .setContentStateVersion(mContentStateVersion)
+                    .setOpenerAppId(mOpenerAppId)
+                    .setThemeColor(mThemeColor)
+                    .setLaunchTypeAtCreation(getLaunchType(mTabLaunchTypeAtCreation))
+                    .build()
+                    .toByteArray();
         }
-        return CriticalPersistedTabDataProto.newBuilder()
-                .setParentId(mParentId)
-                .setRootId(mRootId)
-                .setTimestampMillis(mTimestampMillis)
-                .setWebContentsStateBytes(webContentsState == null
-                                ? ByteString.EMPTY
-                                : ByteString.copyFrom(
-                                        getContentStateByteArray(webContentsState.buffer())))
-                .setContentStateVersion(mContentStateVersion)
-                .setOpenerAppId(mOpenerAppId)
-                .setThemeColor(mThemeColor)
-                .setLaunchTypeAtCreation(getLaunchType(mTabLaunchTypeAtCreation))
-                .build()
-                .toByteArray();
     }
 
     protected static byte[] getContentStateByteArray(ByteBuffer buffer) {
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
index 9797c74..16f780a 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/state/PersistedTabData.java
@@ -188,7 +188,6 @@
     abstract byte[] serialize();
 
     private byte[] serializeAndLog() {
-        // TODO(crbug.com/1119856) Add trace events
         byte[] res = serialize();
         RecordHistogram.recordBooleanHistogram(
                 "Tabs.PersistedTabData.Serialize." + getUmaTag(), res != null);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 9f2cc66c..0c024643 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1353,10 +1353,6 @@
       "webui/nearby_internals/nearby_internals_ui.h",
       "webui/nearby_internals/nearby_internals_ui_trigger_handler.cc",
       "webui/nearby_internals/nearby_internals_ui_trigger_handler.h",
-      "webui/nearby_share/nearby_share_dialog_ui.cc",
-      "webui/nearby_share/nearby_share_dialog_ui.h",
-      "webui/nearby_share/shared_resources.cc",
-      "webui/nearby_share/shared_resources.h",
       "webui/new_tab_page/new_tab_page_handler.cc",
       "webui/new_tab_page/new_tab_page_handler.h",
       "webui/new_tab_page/new_tab_page_ui.cc",
@@ -2363,6 +2359,10 @@
       "webui/help/version_updater_chromeos.h",
       "webui/management_ui_handler_chromeos.cc",
       "webui/management_ui_handler_chromeos.h",
+      "webui/nearby_share/nearby_share_dialog_ui.cc",
+      "webui/nearby_share/nearby_share_dialog_ui.h",
+      "webui/nearby_share/shared_resources.cc",
+      "webui/nearby_share/shared_resources.h",
       "webui/settings/chromeos/about_section.cc",
       "webui/settings/chromeos/about_section.h",
       "webui/settings/chromeos/accessibility_handler.cc",
diff --git a/chrome/browser/ui/views/native_file_system/native_file_system_browsertest.cc b/chrome/browser/ui/views/native_file_system/native_file_system_browsertest.cc
index 9d44050..3daee5d1 100644
--- a/chrome/browser/ui/views/native_file_system/native_file_system_browsertest.cc
+++ b/chrome/browser/ui/views/native_file_system/native_file_system_browsertest.cc
@@ -4,8 +4,11 @@
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_path_override.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/native_file_system/native_file_system_permission_context_factory.h"
@@ -18,21 +21,25 @@
 #include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "chrome/common/chrome_features.h"
+#include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/permissions/permission_util.h"
 #include "components/safe_browsing/buildflags.h"
+#include "content/public/browser/web_ui_controller_factory.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/web_ui_browsertest_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "third_party/blink/public/common/features.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 #include "ui/shell_dialogs/select_file_dialog_factory.h"
 #include "ui/shell_dialogs/select_file_policy.h"
+#include "ui/webui/webui_allowlist.h"
 
 using safe_browsing::ClientDownloadRequest;
 
@@ -717,4 +724,171 @@
                             "self.entry.queryPermission({mode: 'read'})"));
 }
 
+// The helper methods in this class uses ExecuteScriptXXX, because WebUI has
+// a Content Security Policy that interferes with ExecJs and EvalJs.
+class NativeFileSystemBrowserTestForWebUI : public InProcessBrowserTest {
+ public:
+  NativeFileSystemBrowserTestForWebUI() {
+    native_file_system_feature_.InitAndEnableFeature(
+        blink::features::kNativeFileSystemAPI);
+
+    content::WebUIControllerFactory::RegisterFactory(&factory_);
+
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    CHECK(temp_dir_.CreateUniqueTempDir());
+  }
+
+  ~NativeFileSystemBrowserTestForWebUI() override {
+    content::WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
+  }
+
+  // Return the evaluated value of a JavaScript |statement| as a std::string.
+  // The statement can be a Promise that resolves to a string. If errors are
+  // encountered during evaluation, returns the error's message.
+  std::string GetJsStatementValueAsString(content::WebContents* web_contents,
+                                          const std::string& statement) {
+    std::string result;
+    EXPECT_TRUE(content::ExecuteScriptAndExtractString(
+        web_contents,
+        base::StrCat({"Promise.resolve(", statement, ").then(",
+                      "  result => domAutomationController.send(result),"
+                      "  error => domAutomationController.send(error.message)"
+                      ");"}),
+        &result));
+    return result;
+  }
+
+  content::WebContents* SetUpAndNavigateToTestWebUI() {
+    const GURL kWebUITestUrl = content::GetWebUIURL("webui/title1.html");
+    WebUIAllowlist::GetOrCreate(browser()->profile())
+        ->RegisterAutoGrantedPermissions(
+            url::Origin::Create(kWebUITestUrl),
+            {ContentSettingsType::FILE_SYSTEM_READ_GUARD,
+             ContentSettingsType::FILE_SYSTEM_WRITE_GUARD});
+
+    ui_test_utils::NavigateToURL(browser(), kWebUITestUrl);
+    return browser()->tab_strip_model()->GetActiveWebContents();
+  }
+
+  void TestFilePermissionInDirectory(content::WebContents* web_contents,
+                                     const base::FilePath& dir_path) {
+    // Create a test file in the directory.
+    base::FilePath test_file_path;
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      ASSERT_TRUE(base::CreateTemporaryFileInDir(dir_path, &test_file_path));
+      ASSERT_TRUE(base::WriteFile(test_file_path, "test"));
+    }
+
+    // Write permissions are granted to the test WebUI with WebUIAllowlist in
+    // SetUpAndNavigateToTestWebUI. Users should not get permission prompts. We
+    // auto-deny them if they show up.
+    NativeFileSystemPermissionRequestManager::FromWebContents(web_contents)
+        ->set_auto_response_for_test(permissions::PermissionAction::DENIED);
+
+    // Open the dialog and choose the file.
+    ui::SelectFileDialog::SetFactory(
+        new FakeSelectFileDialogFactory({test_file_path}));
+    EXPECT_EQ("ok",
+              GetJsStatementValueAsString(web_contents,
+                                          "window.showOpenFilePicker().then("
+                                          "  handles => {"
+                                          "    window.file_handle = handles[0];"
+                                          "    return 'ok';"
+                                          "})"));
+
+    EXPECT_EQ("file", GetJsStatementValueAsString(web_contents,
+                                                  "window.file_handle.kind"));
+
+    // Check permission descriptors.
+    EXPECT_EQ("granted",
+              GetJsStatementValueAsString(
+                  web_contents,
+                  "window.file_handle.queryPermission({ mode: 'read' })"));
+    EXPECT_EQ("granted",
+              GetJsStatementValueAsString(
+                  web_contents,
+                  "window.file_handle.queryPermission({ mode: 'readwrite' })"));
+  }
+
+  void TestDirectoryPermission(content::WebContents* web_contents,
+                               const base::FilePath& dir_path) {
+    // Write permissions are granted to the test WebUI with WebUIAllowlist in
+    // SetUpAndNavigateToTestWebUI. Users should not get permission prompts. We
+    // auto-deny them if they show up.
+    NativeFileSystemPermissionRequestManager::FromWebContents(web_contents)
+        ->set_auto_response_for_test(permissions::PermissionAction::DENIED);
+
+    // Open the dialog and choose the directory.
+    ui::SelectFileDialog::SetFactory(
+        new FakeSelectFileDialogFactory({dir_path}));
+
+    EXPECT_EQ("ok",
+              GetJsStatementValueAsString(web_contents,
+                                          "window.showDirectoryPicker().then("
+                                          "  handle => {"
+                                          "    window.dir_handle = handle;"
+                                          "    return 'ok';"
+                                          "})"));
+
+    EXPECT_EQ("directory", GetJsStatementValueAsString(
+                               web_contents, "window.dir_handle.kind"));
+
+    // Check permission descriptors.
+    EXPECT_EQ("granted",
+              GetJsStatementValueAsString(
+                  web_contents,
+                  "window.dir_handle.queryPermission({ mode: 'read' })"));
+    EXPECT_EQ("granted",
+              GetJsStatementValueAsString(
+                  web_contents,
+                  "window.dir_handle.queryPermission({ mode: 'readwrite' })"));
+  }
+
+ protected:
+  base::ScopedTempDir temp_dir_;
+
+ private:
+  base::test::ScopedFeatureList native_file_system_feature_;
+  content::TestWebUIControllerFactory factory_;
+};
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTestForWebUI,
+                       OpenFilePicker_NormalPath) {
+  content::WebContents* web_contents = SetUpAndNavigateToTestWebUI();
+  TestFilePermissionInDirectory(web_contents, temp_dir_.GetPath());
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTestForWebUI,
+                       OpenFilePicker_FileInSensitivePath) {
+  base::ScopedPathOverride downloads_override(
+      chrome::DIR_DEFAULT_DOWNLOADS, temp_dir_.GetPath(), /*is_absolute*/ true,
+      /*create*/ false);
+
+  content::WebContents* web_contents = SetUpAndNavigateToTestWebUI();
+  TestFilePermissionInDirectory(web_contents, temp_dir_.GetPath());
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTestForWebUI,
+                       OpenDirectoryPicker_NormalPath) {
+  content::WebContents* web_contents = SetUpAndNavigateToTestWebUI();
+  TestDirectoryPermission(web_contents, temp_dir_.GetPath());
+}
+
+IN_PROC_BROWSER_TEST_F(NativeFileSystemBrowserTestForWebUI,
+                       OpenDirectoryPicker_DirectoryInSensitivePath) {
+  base::ScopedPathOverride downloads_override(
+      chrome::DIR_DEFAULT_DOWNLOADS, temp_dir_.GetPath(), /*is_absolute*/ true,
+      /*create*/ false);
+
+  base::FilePath test_dir_path = temp_dir_.GetPath().AppendASCII("folder");
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    ASSERT_TRUE(CreateDirectory(test_dir_path));
+  }
+
+  content::WebContents* web_contents = SetUpAndNavigateToTestWebUI();
+  TestDirectoryPermission(web_contents, test_dir_path);
+}
+
 // TODO(mek): Add more end-to-end test including other bits of UI.
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index b10b0b72..506ca036 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -544,10 +544,6 @@
   if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
     if (url.host_piece() == chrome::kChromeUINearbyInternalsHost)
       return &NewWebUI<NearbyInternalsUI>;
-    if (url.host_piece() == chrome::kChromeUINearbyShareHost &&
-        profile->IsRegularProfile()) {
-      return &NewWebUI<nearby_share::NearbyShareDialogUI>;
-    }
   }
   if (url.host_piece() == chrome::kChromeUINewTabHost)
     return &NewWebUI<NewTabUI>;
@@ -673,6 +669,12 @@
     return &NewWebUI<chromeos::InternetConfigDialogUI>;
   if (url.host_piece() == chrome::kChromeUIInternetDetailDialogHost)
     return &NewWebUI<chromeos::InternetDetailDialogUI>;
+  if (base::FeatureList::IsEnabled(features::kNearbySharing)) {
+    if (url.host_piece() == chrome::kChromeUINearbyShareHost &&
+        profile->IsRegularProfile()) {
+      return &NewWebUI<nearby_share::NearbyShareDialogUI>;
+    }
+  }
   if (url.host_piece() == chrome::kChromeUISetTimeHost)
     return &NewWebUI<chromeos::SetTimeUI>;
   if (url.host_piece() == chrome::kChromeUISlowHost)
diff --git a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
index bdf25eb..1ab78de8 100644
--- a/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
+++ b/chrome/browser/ui/webui/nearby_share/nearby_share_dialog_ui.cc
@@ -50,7 +50,7 @@
   html_source->AddResourcePath("nearby_share_target_types.mojom-lite.js",
                                IDR_NEARBY_SHARE_TARGET_TYPES_MOJO_JS);
 
-  RegisterNearbySharedMojoResources(html_source);
+  RegisterNearbySharedResources(html_source);
   RegisterNearbySharedStrings(html_source);
   html_source->UseStringsJs();
 
diff --git a/chrome/browser/ui/webui/nearby_share/shared_resources.cc b/chrome/browser/ui/webui/nearby_share/shared_resources.cc
index 2ecee45..550195b 100644
--- a/chrome/browser/ui/webui/nearby_share/shared_resources.cc
+++ b/chrome/browser/ui/webui/nearby_share/shared_resources.cc
@@ -7,30 +7,56 @@
 #include <string>
 
 #include "base/containers/span.h"
+#include "base/logging.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/nearby_share_dialog_resources.h"
 #include "chrome/grit/nearby_share_dialog_resources_map.h"
+#include "chrome/grit/nearby_shared_resources.h"
+#include "chrome/grit/nearby_shared_resources_map.h"
+#include "chrome/grit/nearby_shared_resources_v3.h"
+#include "chrome/grit/nearby_shared_resources_v3_map.h"
 #include "ui/base/webui/web_ui_util.h"
 
 const char kNearbyShareGeneratedPath[] =
     "@out_folder@/gen/chrome/browser/resources/nearby_share/";
 
+namespace {
+
+void RegisterResourcesWithPrefix(
+    content::WebUIDataSource* data_source,
+    const base::span<const GritResourceMap>& resources,
+    std::string prefix) {
+  std::string generate_path{kNearbyShareGeneratedPath};
+  for (const GritResourceMap& resource : resources) {
+    std::string path = resource.name;
+    if (path.rfind(generate_path, 0) == 0) {
+      path = path.substr(generate_path.size());
+    } else {
+      path = prefix + path;
+    }
+    data_source->AddResourcePath(path, resource.value);
+  }
+}
+
+}  // namespace
+
 void RegisterNearbySharedMojoResources(content::WebUIDataSource* data_source) {
   data_source->AddResourcePath("mojo/nearby_share_settings.mojom-lite.js",
                                IDR_NEARBY_SHARE_SETTINGS_MOJOM_LITE_JS);
 }
 
 void RegisterNearbySharedResources(content::WebUIDataSource* data_source) {
-  std::string generate_path{kNearbyShareGeneratedPath};
-  for (const GritResourceMap& resource : base::make_span(
-           kNearbyShareDialogResources, kNearbyShareDialogResourcesSize)) {
-    std::string path = resource.name;
-    if (path.rfind(generate_path, 0) == 0) {
-      path = path.substr(generate_path.size());
-    }
-    data_source->AddResourcePath(path, resource.value);
-  }
+  RegisterResourcesWithPrefix(
+      data_source,
+      /*resources=*/
+      base::make_span(kNearbySharedResources, kNearbySharedResourcesSize),
+      /*prefix=*/"shared/");
+  RegisterResourcesWithPrefix(
+      data_source,
+      /*resources=*/
+      base::make_span(kNearbySharedResourcesV3, kNearbySharedResourcesV3Size),
+      /*prefix=*/"shared/");
   RegisterNearbySharedMojoResources(data_source);
 }
 
@@ -38,6 +64,17 @@
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"secureConnectionId", IDS_NEARBY_SECURE_CONNECTION_ID},
       {"nearbyShareFeatureName", IDS_NEARBY_SHARE_FEATURE_NAME},
+      {"visibilityAllContacts", IDS_NEARBY_VISIBLITY_ALL_CONTACTS},
+      {"visibilityAllContactsDescription",
+       IDS_NEARBY_VISIBLITY_ALL_CONTACTS_DESCRIPTION},
+      {"visibilitySomeContacts", IDS_NEARBY_VISIBLITY_SOME_CONTACTS},
+      {"visibilitySomeContactsDescription",
+       IDS_NEARBY_VISIBLITY_SOME_CONTACTS_DESCRIPTION},
+      {"visibilityHidden", IDS_NEARBY_VISIBLITY_HIDDEN},
+      {"visibilityHiddenDescription", IDS_NEARBY_VISIBLITY_HIDDEN_DESCRIPTION},
+      {"visibilityUnknown", IDS_NEARBY_VISIBLITY_UNKNOWN},
+      {"visibilityUnknownDescription",
+       IDS_NEARBY_VISIBLITY_UNKNOWN_DESCRIPTION},
   };
   webui::AddLocalizedStringsBulk(data_source, kLocalizedStrings);
 }
diff --git a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
index ef09fb7..b700648b 100644
--- a/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/apps_section.cc
@@ -238,6 +238,8 @@
 }
 
 void AppsSection::RegisterHierarchy(HierarchyGenerator* generator) const {
+  generator->RegisterTopLevelSetting(mojom::Setting::kTurnOnPlayStore);
+
   // Manage apps.
   generator->RegisterTopLevelSubpage(IDS_SETTINGS_APPS_LINK_TEXT,
                                      mojom::Subpage::kAppManagement,
@@ -266,10 +268,11 @@
   static constexpr mojom::Setting kGooglePlayStoreSettings[] = {
       mojom::Setting::kManageAndroidPreferences,
       mojom::Setting::kRemovePlayStore,
-      mojom::Setting::kTurnOnPlayStore,
   };
   RegisterNestedSettingBulk(mojom::Subpage::kGooglePlayStore,
                             kGooglePlayStoreSettings, generator);
+  generator->RegisterTopLevelAltSetting(
+      mojom::Setting::kManageAndroidPreferences);
 }
 
 void AppsSection::OnAppRegistered(const std::string& app_id,
diff --git a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
index b248e7b8..460d0994 100644
--- a/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/multidevice_section.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/chromeos/android_sms/android_sms_service.h"
 #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/nearby_share/shared_resources.h"
 #include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/search/search_tag_registry.h"
 #include "chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h"
@@ -324,6 +325,7 @@
 
   AddEasyUnlockStrings(html_source);
   ::settings::AddNearbyShareData(html_source);
+  RegisterNearbySharedStrings(html_source);
 }
 
 void MultiDeviceSection::AddHandlers(content::WebUI* web_ui) {
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
index 2fecfec..377fd9d 100644
--- a/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_ui.cc
@@ -87,6 +87,10 @@
                                  IDR_OS_SETTINGS_LAZY_LOAD_VULCANIZED_HTML);
     html_source->SetDefaultResource(IDR_OS_SETTINGS_VULCANIZED_HTML);
   }
+
+  // We only need to register the mojo resources here because the rest are
+  // bundled in.
+  RegisterNearbySharedMojoResources(html_source);
 #else
   webui::SetupWebUIDataSource(
       html_source,
@@ -95,13 +99,15 @@
       base::FeatureList::IsEnabled(chromeos::features::kOsSettingsPolymer3)
           ? IDR_OS_SETTINGS_OS_SETTINGS_V3_HTML
           : IDR_OS_SETTINGS_SETTINGS_HTML);
-#endif
 
   // Register chrome://nearby resources so they are available at
   // chrome://os-settings. This allows the sharing of resources without having
   // to put everything in chrome://resources. This is necessary because portions
   // of the nearby UI need to be re-used in both places.
+  // This is not nessary when OPTIMIZE_WEBUI is true because the files will be
+  // added to the optimized bundles.
   RegisterNearbySharedResources(html_source);
+#endif
 
   ManagedUIHandler::Initialize(web_ui, html_source);
 
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index 721c9aa..ca940d30 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -278,7 +278,13 @@
       {"nearbyShareDataUsageWifiOnlyEditButtonDescription",
        IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_WIFI_ONLY_DESCRIPTION},
       {"nearbyShareDataUsageOfflineEditButtonDescription",
-       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_OFFLINE_DESCRIPTION}};
+       IDS_SETTINGS_NEARBY_SHARE_DATA_USAGE_EDIT_BUTTON_OFFLINE_DESCRIPTION},
+      {"nearbyShareContactVisibilityRowTitle",
+       IDS_SETTINGS_NEARBY_SHARE_CONTACT_VISIBILITY_ROW_TITLE},
+      {"nearbyShareEditVisibility", IDS_SETTINGS_NEARBY_SHARE_EDIT_VISIBILITY},
+      {"nearbyShareVisibilityDialogTitle",
+       IDS_SETTINGS_NEARBY_SHARE_VISIBILITY_DIALOG_TITLE}};
+
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 
   html_source->AddBoolean(
diff --git a/chrome/browser/vr/test/multi_class_browser_test.h b/chrome/browser/vr/test/multi_class_browser_test.h
index acde8f44..28ac31e4 100644
--- a/chrome/browser/vr/test/multi_class_browser_test.h
+++ b/chrome/browser/vr/test/multi_class_browser_test.h
@@ -63,6 +63,17 @@
     MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread(this); \
   }
 
+// In this case IN_PROC_BROWSER_TEST_F could realistically be used; however, in
+// some cases, we're conditionally enabling runtimes. This method thus enables
+// easily "switching" between having only one runtime enabled and having two or
+// more runtimes enabled, and helps make the "ALL_RUNTIMES" macros possible.
+#define IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(test_class1, base_class,     \
+                                            test_name)                   \
+  DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
+  DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
+  void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
+      base_class* t)
+
 #define IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(test_class1, test_class2,    \
                                             base_class, test_name)       \
   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
@@ -71,15 +82,6 @@
   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
       base_class* t)
 
-#define IN_PROC_MULTI_CLASS_BROWSER_TEST_F3(                             \
-    test_class1, test_class2, test_class3, base_class, test_name)        \
-  DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
-  DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
-  DEFINE_BROWSER_TEST_(test_class2, test_name)                           \
-  DEFINE_BROWSER_TEST_(test_class3, test_name)                           \
-  void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
-      base_class* t)
-
 #define IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F2(              \
     test_class1, test_class2, base_class, test_name)                     \
   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
@@ -90,45 +92,43 @@
   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
       base_class* t)
 
-#define IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F3(              \
-    test_class1, test_class2, test_class3, base_class, test_name)        \
+// In this case IN_PROC_BROWSER_TEST_F could realistically be used; however, in
+// some cases, we're conditionally enabling runtimes. This method thus enables
+// easily "switching" between having only one runtime enabled and having two or
+// more runtimes enabled, and helps make the "ALL_RUNTIMES" macros possible.
+#define IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F1(              \
+    test_class1, base_class, test_name)                                  \
   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
   DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
-  DEFINE_BROWSER_TEST_(test_class2, test_name)                           \
-  DEFINE_BROWSER_TEST_(test_class3, test_name)                           \
   DEFINE_INCOGNITO_BROWSER_TEST_(test_class1, test_name)                 \
-  DEFINE_INCOGNITO_BROWSER_TEST_(test_class2, test_name)                 \
-  DEFINE_INCOGNITO_BROWSER_TEST_(test_class3, test_name)                 \
   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
       base_class* t)
 
 // Helper macro to cut down on duplicate code since most uses of
-// IN_PROC_MULTI_CLASS_BROWSER_TEST_F3 are passed the same OpenVR, WMR, and
-// OpenXR classes and the same base class
+// IN_PROC_MULTI_CLASS_BROWSER_TEST_F2 are passed the same WMR, and OpenXR
+// classes and the same base class
 #if BUILDFLAG(ENABLE_OPENXR)
-#define WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(test_name) \
-  IN_PROC_MULTI_CLASS_BROWSER_TEST_F3(                  \
-      WebXrVrOpenVrBrowserTest, WebXrVrWmrBrowserTest,  \
-      WebXrVrOpenXrBrowserTest, WebXrVrBrowserTestBase, test_name)
-#else
 #define WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(test_name)         \
-  IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTest, \
-                                      WebXrVrWmrBrowserTest,    \
+  IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrWmrBrowserTest,    \
+                                      WebXrVrOpenXrBrowserTest, \
+                                      WebXrVrBrowserTestBase, test_name)
+#else
+#define WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(test_name)      \
+  IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(WebXrVrWmrBrowserTest, \
                                       WebXrVrBrowserTestBase, test_name)
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
 // The same as WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F, but runs the tests in
 // incognito mode as well.
 #if BUILDFLAG(ENABLE_OPENXR)
-#define WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(test_name) \
-  IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F3(                  \
-      WebXrVrOpenVrBrowserTest, WebXrVrWmrBrowserTest,                 \
-      WebXrVrOpenXrBrowserTest, WebXrVrBrowserTestBase, test_name)
-#else
 #define WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(test_name)         \
   IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F2(                          \
-      WebXrVrOpenVrBrowserTest, WebXrVrWmrBrowserTest, WebXrVrBrowserTestBase, \
+      WebXrVrOpenXrBrowserTest, WebXrVrWmrBrowserTest, WebXrVrBrowserTestBase, \
       test_name)
+#else
+#define WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(test_name) \
+  IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F1(                  \
+      WebXrVrWmrBrowserTest, WebXrVrBrowserTestBase, test_name)
 #endif  // ENABLE_OPENXR
 
 // Helper class to disable a specific runtime of the above
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.cc b/chrome/browser/vr/test/webxr_vr_browser_test.cc
index ef5ea86..43366f21 100644
--- a/chrome/browser/vr/test/webxr_vr_browser_test.cc
+++ b/chrome/browser/vr/test/webxr_vr_browser_test.cc
@@ -99,28 +99,6 @@
 
 #if defined(OS_WIN)
 
-WebXrVrOpenVrBrowserTestBase::WebXrVrOpenVrBrowserTestBase() {
-  enable_features_.push_back(device::features::kOpenVR);
-#if BUILDFLAG(ENABLE_WINDOWS_MR)
-  disable_features_.push_back(device::features::kWindowsMixedReality);
-#endif
-#if BUILDFLAG(ENABLE_OPENXR)
-  disable_features_.push_back(device::features::kOpenXR);
-#endif
-}
-
-XrBrowserTestBase::RuntimeType WebXrVrOpenVrBrowserTestBase::GetRuntimeType()
-    const {
-  return XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR;
-}
-
-gfx::Vector3dF WebXrVrOpenVrBrowserTestBase::GetControllerOffset() const {
-  // The 0.08f comes from the slight adjustment we perform in
-  // openvr_render_loop.cc to account for OpenVR reporting the controller
-  // position at the tip, but WebXR using the position at the grip.
-  return gfx::Vector3dF(0, 0, 0.08f);
-}
-
 WebXrVrWmrBrowserTestBase::WebXrVrWmrBrowserTestBase() {
 #if BUILDFLAG(ENABLE_WINDOWS_MR)
   enable_features_.push_back(device::features::kWindowsMixedReality);
@@ -159,12 +137,6 @@
 }
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
-WebXrVrOpenVrBrowserTest::WebXrVrOpenVrBrowserTest() {
-  // We know at this point that we're going to be running with both OpenVR and
-  // WebXR enabled, so enforce the DirectX 11.1 requirement.
-  runtime_requirements_.push_back(XrTestRequirement::DIRECTX_11_1);
-}
-
 WebXrVrWmrBrowserTest::WebXrVrWmrBrowserTest() {
   runtime_requirements_.push_back(XrTestRequirement::DIRECTX_11_1);
 }
@@ -176,10 +148,6 @@
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
 // Test classes with WebXR disabled.
-WebXrVrOpenVrBrowserTestWebXrDisabled::WebXrVrOpenVrBrowserTestWebXrDisabled() {
-  disable_features_.push_back(features::kWebXr);
-}
-
 WebXrVrWmrBrowserTestWebXrDisabled::WebXrVrWmrBrowserTestWebXrDisabled() {
   disable_features_.push_back(features::kWebXr);
 }
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.h b/chrome/browser/vr/test/webxr_vr_browser_test.h
index d651d20..15c5dac 100644
--- a/chrome/browser/vr/test/webxr_vr_browser_test.h
+++ b/chrome/browser/vr/test/webxr_vr_browser_test.h
@@ -53,7 +53,7 @@
           permissions::PermissionRequestManager::ACCEPT_ALL;
 };
 
-// Test class with OpenVR disabled.
+// Test class with all runtimes disabled.
 class WebXrVrRuntimelessBrowserTest : public WebXrVrBrowserTestBase {
  public:
   WebXrVrRuntimelessBrowserTest();
@@ -65,16 +65,8 @@
   WebXrVrRuntimelessBrowserTestSensorless();
 };
 
-// OpenVR and WMR feature only defined on Windows.
+// WMR feature only defined on Windows.
 #ifdef OS_WIN
-// OpenVR-specific subclass of WebXrVrBrowserTestBase.
-class WebXrVrOpenVrBrowserTestBase : public WebXrVrBrowserTestBase {
- public:
-  WebXrVrOpenVrBrowserTestBase();
-  XrBrowserTestBase::RuntimeType GetRuntimeType() const override;
-  gfx::Vector3dF GetControllerOffset() const override;
-};
-
 // WMR-specific subclass of WebXrVrBrowserTestBase.
 class WebXrVrWmrBrowserTestBase : public WebXrVrBrowserTestBase {
  public:
@@ -102,12 +94,6 @@
 };
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
-// Test class with standard features enabled: WebXR and OpenVR.
-class WebXrVrOpenVrBrowserTest : public WebXrVrOpenVrBrowserTestBase {
- public:
-  WebXrVrOpenVrBrowserTest();
-};
-
 class WebXrVrWmrBrowserTest : public WebXrVrWmrBrowserTestBase {
  public:
   WebXrVrWmrBrowserTest();
@@ -120,13 +106,6 @@
 };
 #endif  // BUILDFLAG(ENABLE_OPENXR)
 
-// Test classes with WebXR disabled.
-class WebXrVrOpenVrBrowserTestWebXrDisabled
-    : public WebXrVrOpenVrBrowserTestBase {
- public:
-  WebXrVrOpenVrBrowserTestWebXrDisabled();
-};
-
 class WebXrVrWmrBrowserTestWebXrDisabled : public WebXrVrWmrBrowserTestBase {
  public:
   WebXrVrWmrBrowserTestWebXrDisabled();
diff --git a/chrome/browser/vr/test/xr_browser_test.h b/chrome/browser/vr/test/xr_browser_test.h
index b1f340e..27c13b8 100644
--- a/chrome/browser/vr/test/xr_browser_test.h
+++ b/chrome/browser/vr/test/xr_browser_test.h
@@ -73,7 +73,6 @@
 
   enum class RuntimeType {
     RUNTIME_NONE = 0,
-    RUNTIME_OPENVR = 1,
     RUNTIME_WMR = 2,
     RUNTIME_OPENXR = 3
   };
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc
index 62270858..4d59c08 100644
--- a/chrome/browser/vr/webxr_vr_input_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/vr/test/multi_class_browser_test.h"
 #include "chrome/browser/vr/test/webxr_vr_browser_test.h"
 #include "device/vr/public/mojom/browser_test_interfaces.mojom.h"
-#include "third_party/openvr/src/headers/openvr.h"
 
 // Browser test equivalent of
 // chrome/android/javatests/src/.../browser/vr/WebXrVrInputTest.java.
@@ -355,139 +354,6 @@
   t->EndTest();
 }
 
-// Ensure that when an input source's profiles array changes, an input source
-// change event is fired and a new input source is created.
-// OpenVR-only since WMR/OpenXR only supports one kind of gamepad, so it's not
-// possible to update the connected gamepad functionality to force the profiles
-// array to change.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputProfilesChange) {
-  WebXrControllerInputMock my_mock;
-  unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
-
-  LoadFileAndAwaitInitialization("test_webxr_input_same_object");
-  EnterSessionWithUserGestureOrFail();
-
-  // Wait for the first changed event
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 1",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-
-  // We only expect one input source, cache it.
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("updateCachedInputSource(0)");
-
-  // Add a touchpad so that the profiles array changes and verify that we get a
-  // change event.
-  uint64_t supported_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrackpad);
-  std::map<device::XrButtonId, unsigned int> axis_types = {
-      {device::XrButtonId::kAxisTrackpad, device::XrAxisType::kTrackpad},
-      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
-  };
-  my_mock.UpdateControllerSupport(controller_index, axis_types,
-                                  supported_buttons);
-
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 2",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-  RunJavaScriptOrFail("validateCachedSourcePresence(false)");
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
-// Ensure that changes to a gamepad object respect that it is the same object
-// and that if whether or not an input source has a gamepad changes that the
-// input source change event is fired and a new input source is created.
-// OpenVR-only since WMR/OpenXR doesn't support the notion of an incomplete
-// gamepad except if using voice input.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputGamepadSameObject) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a set of buttons and axes that don't have enough data to be made
-  // into an xr-standard gamepad (which we expect the runtimes to not report).
-  // Even just setting the select trigger is now enough to create an xr-standard
-  // gamepad, so we only set the grip trigger in this case.
-  uint64_t insufficient_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kGrip);
-  std::map<device::XrButtonId, unsigned int> insufficient_axis_types = {};
-
-  // Create a set of buttons and axes that we expect to have enough data to be
-  // made into an xr-standard gamepad (which we expect the runtimes to report).
-  uint64_t sufficient_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrackpad);
-  std::map<device::XrButtonId, unsigned int> sufficient_axis_types = {
-      {device::XrButtonId::kAxisTrackpad, device::XrAxisType::kTrackpad},
-      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
-  };
-
-  // Start off without a gamepad.
-  unsigned int controller_index = my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, insufficient_axis_types,
-      insufficient_buttons);
-
-  LoadFileAndAwaitInitialization("test_webxr_input_same_object");
-  EnterSessionWithUserGestureOrFail();
-
-  // We should only have seen the first change indicating we have input sources.
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 1", kPollTimeoutShort);
-
-  // We only expect one input source, cache it.
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("updateCachedInputSource(0)");
-
-  // Toggle a button and confirm that the controller is still the same.
-  my_mock.ToggleButtons(controller_index, insufficient_buttons);
-  RunJavaScriptOrFail("validateCachedSourcePresence(true)");
-  RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()");
-
-  // Update the controller to now support a gamepad and verify that we get a
-  // change event and that the old controller isn't present.  Then cache the new
-  // one.
-  my_mock.UpdateControllerSupport(controller_index, sufficient_axis_types,
-                                  sufficient_buttons);
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 2", kPollTimeoutShort);
-  RunJavaScriptOrFail("validateCachedSourcePresence(false)");
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("updateCachedInputSource(0)");
-
-  // Toggle a button and confirm that the controller is still the same.
-  my_mock.PressReleasePrimaryTrigger(controller_index);
-  RunJavaScriptOrFail("validateCachedSourcePresence(true)");
-  RunJavaScriptOrFail("validateCurrentAndCachedGamepadMatch()");
-
-  // Switch back to the insufficient gamepad and confirm that we get the change.
-  my_mock.UpdateControllerSupport(controller_index, insufficient_axis_types,
-                                  insufficient_buttons);
-  PollJavaScriptBooleanOrFail("inputChangeEvents === 3", kPollTimeoutShort);
-  RunJavaScriptOrFail("validateCachedSourcePresence(false)");
-  RunJavaScriptOrFail("validateInputSourceLength(1)");
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
-// Ensure that if the controller lacks enough data to be considered a Gamepad
-// that the input source that it is associated with does not have a Gamepad.
-// OpenVR-only because WMR/OpenXR does not currently support the notion of
-// incomplete gamepads other than voice input.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadIncompleteData) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a controller that only supports select, i.e. it lacks enough data
-  // to be considered a gamepad.
-  uint64_t supported_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger);
-  my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, {}, supported_buttons);
-
-  LoadFileAndAwaitInitialization("test_webxr_gamepad_support");
-  EnterSessionWithUserGestureOrFail();
-  PollJavaScriptBooleanOrFail("inputSourceHasNoGamepad()", kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isProfileCountEqualTo(0)", kPollTimeoutShort);
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
 // Ensure that if a Gamepad has the minimum required number of axes/buttons to
 // be considered an xr-standard Gamepad, that it is exposed as such, and that
 // we can check the state of it's priamry axes/button.
@@ -531,10 +397,6 @@
         t, {"windows-mixed-reality",
             "generic-trigger-squeeze-touchpad-thumbstick"});
   } else if (t->GetRuntimeType() ==
-             XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
-    VerifyInputSourceProfilesArray(
-        t, {"test-value-test-value", "generic-trigger"});
-  } else if (t->GetRuntimeType() ==
              XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
     // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
     // because it only supports that type of controller and fills in default
@@ -613,10 +475,6 @@
         t, {"windows-mixed-reality",
             "generic-trigger-squeeze-touchpad-thumbstick"});
   } else if (t->GetRuntimeType() ==
-             XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
-    VerifyInputSourceProfilesArray(
-        t, {"test-value-test-value", "generic-trigger"});
-  } else if (t->GetRuntimeType() ==
              XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
     // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
     // because it only supports that type of controller and fills in default
@@ -721,11 +579,6 @@
         t, {"windows-mixed-reality",
             "generic-trigger-squeeze-touchpad-thumbstick"});
   } else if (t->GetRuntimeType() ==
-             XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR) {
-    VerifyInputSourceProfilesArray(
-        t, {"test-value-test-value",
-            "generic-trigger-squeeze-touchpad-thumbstick"});
-  } else if (t->GetRuntimeType() ==
              XrBrowserTestBase::RuntimeType::RUNTIME_OPENXR) {
     // OpenXR will still report having squeeze, menu, touchpad, and thumbstick
     // because it only supports that type of controller and fills in default
@@ -739,161 +592,6 @@
   t->EndTest();
 }
 
-// Tests that axes data is still reported on the secondary axes even if
-// the button is not supported (we see this case with WMR through OpenVR where
-// the secondary axes button is reserved by the system, but we still get valid
-// data for the axes, there may be other controllers where this is the case).
-// Because this is specifically a bug in the OpenVR runtime/with configurable
-// controllers, not testing WMR/OpenXR.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestInputAxesWithNoButton) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a controller that supports all reserved buttons, except the
-  // secondary axis. (Though it is a valid axis)
-  uint64_t supported_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrackpad) |
-      device::XrButtonMaskFromId(device::XrButtonId::kGrip);
-
-  std::map<device::XrButtonId, unsigned int> axis_types = {
-      {device::XrButtonId::kAxisTrackpad, device::XrAxisType::kTrackpad},
-      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
-      {device::XrButtonId::kAxisThumbstick, device::XrAxisType::kJoystick},
-  };
-
-  unsigned int controller_index = my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, axis_types,
-      supported_buttons);
-
-  LoadFileAndAwaitInitialization("test_webxr_gamepad_support");
-  EnterSessionWithUserGestureOrFail();
-
-  VerifyInputCounts(this, 1, 1);
-
-  // Setup some state on the optional buttons (as TestGamepadMinimumData should
-  // ensure proper state on the required buttons).
-  // Set a value on the secondary set of axes.
-  my_mock.SetAxes(controller_index, device::XrButtonId::kAxisThumbstick, 0.25,
-                  -0.25);
-  // Controller should meet the requirements for the 'xr-standard' mapping.
-  PollJavaScriptBooleanOrFail("isMappingEqualTo('xr-standard')",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-
-  // Controller should have all required and optional xr-standard buttons
-  PollJavaScriptBooleanOrFail("isButtonCountEqualTo(4)",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-
-  // The secondary set of axes should be set appropriately.
-  PollJavaScriptBooleanOrFail("areAxesValuesEqualTo(1, 0.25, -0.25)",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-
-  // If we have a non-zero axis value, the button should be touched.
-  PollJavaScriptBooleanOrFail("isButtonTouchedEqualTo(3, true)",
-                              WebXrVrBrowserTestBase::kPollTimeoutShort);
-
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
-// Ensure that if a Gamepad has all required buttons, an extra button not
-// mapped in the xr-standard specification, and is missing reserved buttons
-// from the XR Standard specification, that the extra button does not appear
-// in either of the reserved button slots. OpenVR-only since WMR/OpenXR only
-// supports one controller type.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadReservedData) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a controller that is missing reserved buttons, but supports an
-  // extra button to guarantee that the reserved button is held.
-  uint64_t supported_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrackpad) |
-      device::XrButtonMaskFromId(device::XrButtonId::kA);
-
-  std::map<device::XrButtonId, unsigned int> axis_types = {
-      {device::XrButtonId::kAxisTrackpad, device::XrAxisType::kTrackpad},
-      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
-  };
-
-  unsigned int controller_index = my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, axis_types,
-      supported_buttons);
-
-  LoadFileAndAwaitInitialization("test_webxr_gamepad_support");
-  EnterSessionWithUserGestureOrFail();
-
-  VerifyInputCounts(this, 1, 1);
-
-  // Claim that all buttons are pressed, note that any non-supported buttons
-  // should be ignored.
-  my_mock.ToggleButtons(controller_index, UINT64_MAX);
-
-  // Index 1 and 3 are reserved for the grip and joystick.
-  // As our controller doesn't support them, they should be present but not
-  // pressed, and our "extra" button should be index 4 and should be pressed.
-  PollJavaScriptBooleanOrFail("isMappingEqualTo('xr-standard')",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonCountEqualTo(5)", kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonPressedEqualTo(0, true)",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonPressedEqualTo(1, false)",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonPressedEqualTo(2, true)",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonPressedEqualTo(3, false)",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonPressedEqualTo(4, true)",
-                              kPollTimeoutShort);
-
-  VerifyInputSourceProfilesArray(
-      this, {"test-value-test-value", "generic-trigger-touchpad"});
-
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
-// Ensure that if a gamepad has a grip, but not any extra buttons or a secondary
-// axis, that no trailing placeholder button is added.  This is a slight
-// variation on TestGamepadMinimalData, but won't re-test whether or not buttons
-// get sent up.  Note that since WMR/OpenXR always builds the WMR/OpenXR
-// controller which supports all required and optional buttons specified by the
-// xr-standard mapping, this test is OpenVR-only.
-IN_PROC_BROWSER_TEST_F(WebXrVrOpenVrBrowserTest, TestGamepadOptionalData) {
-  WebXrControllerInputMock my_mock;
-
-  // Create a controller that supports the trigger, primary axis, and grip
-  uint64_t supported_buttons =
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrigger) |
-      device::XrButtonMaskFromId(device::XrButtonId::kAxisTrackpad) |
-      device::XrButtonMaskFromId(device::XrButtonId::kGrip);
-
-  std::map<device::XrButtonId, unsigned int> axis_types = {
-      {device::XrButtonId::kAxisTrackpad, device::XrAxisType::kTrackpad},
-      {device::XrButtonId::kAxisTrigger, device::XrAxisType::kTrigger},
-  };
-
-  my_mock.CreateAndConnectController(
-      device::ControllerRole::kControllerRoleRight, axis_types,
-      supported_buttons);
-
-  LoadFileAndAwaitInitialization("test_webxr_gamepad_support");
-  EnterSessionWithUserGestureOrFail();
-
-  VerifyInputCounts(this, 1, 1);
-
-  // There should be enough buttons for an xr-standard mapping, and it should
-  // have one optional button, but not the other.
-  PollJavaScriptBooleanOrFail("isMappingEqualTo('xr-standard')",
-                              kPollTimeoutShort);
-  PollJavaScriptBooleanOrFail("isButtonCountEqualTo(3)", kPollTimeoutShort);
-
-  VerifyInputSourceProfilesArray(
-      this, {"test-value-test-value", "generic-trigger-squeeze-touchpad"});
-
-  RunJavaScriptOrFail("done()");
-  EndTest();
-}
-
 #if BUILDFLAG(ENABLE_OPENXR)
 // Ensure that if OpenXR Runtime receive interaction profile chagnes event,
 // input profile name will be changed accordingly.
@@ -1000,8 +698,6 @@
 // Equivalent to
 // WebXrVrInputTest#testControllerClicksRegisteredOnDaydream_WebXr.
 WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(TestControllerInputRegistered) {
-  // TODO(crbug.com/1033087): Test is flaky on OpenVR
-  WEBXR_VR_DISABLE_TEST_ON(XrBrowserTestBase::RuntimeType::RUNTIME_OPENVR);
   WebXrControllerInputMock my_mock;
 
   unsigned int controller_index = my_mock.CreateAndConnectMinimalGamepad();
diff --git a/chrome/browser/vr/webxr_vr_transition_browser_test.cc b/chrome/browser/vr/webxr_vr_transition_browser_test.cc
index e5b64957..a7d090cd 100644
--- a/chrome/browser/vr/webxr_vr_transition_browser_test.cc
+++ b/chrome/browser/vr/webxr_vr_transition_browser_test.cc
@@ -37,14 +37,12 @@
 #ifdef OS_WIN
 
 #if BUILDFLAG(ENABLE_OPENXR)
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F3(WebXrVrOpenVrBrowserTestWebXrDisabled,
-                                    WebXrVrWmrBrowserTestWebXrDisabled,
+IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrWmrBrowserTestWebXrDisabled,
                                     WebXrVrOpenXrBrowserTestWebXrDisabled,
                                     WebXrVrBrowserTestBase,
                                     TestWebXrDisabledWithoutFlagSet) {
 #else
-IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrOpenVrBrowserTestWebXrDisabled,
-                                    WebXrVrWmrBrowserTestWebXrDisabled,
+IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(WebXrVrWmrBrowserTestWebXrDisabled,
                                     WebXrVrBrowserTestBase,
                                     TestWebXrDisabledWithoutFlagSet) {
 #endif  // BUILDFLAG(ENABLE_OPENXR)
diff --git a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
index 32c982a..d5a4bd3 100644
--- a/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/system_web_app_manager_browsertest.cc
@@ -368,6 +368,9 @@
   histograms.ExpectUniqueSample("Apps.DefaultAppLaunch.FromAppListGrid", 39, 1);
 }
 
+// The helper methods in this class uses ExecuteScriptXXX instead of ExecJs and
+// EvalJs because of some quirks surrounding origin trials and content security
+// policies.
 class SystemWebAppManagerFileHandlingBrowserTestBase
     : public SystemWebAppManagerBrowserTestBase,
       public ::testing::WithParamInterface<ProviderTypeAndInstallationType> {
@@ -472,8 +475,6 @@
 };
 
 // Check launch files are passed to application.
-// Note: This test uses ExecuteScriptXXX instead of ExecJs and EvalJs because of
-// some quirks surrounding origin trials and content security policies.
 IN_PROC_BROWSER_TEST_P(SystemWebAppManagerLaunchFilesBrowserTest,
                        LaunchFilesForSystemWebApp) {
   WaitForTestSystemAppInstall();
@@ -512,6 +513,9 @@
                                         "window.launchParams2.files[0].name"));
 }
 
+// The helper methods in this class uses ExecuteScriptXXX instead of ExecJs and
+// EvalJs because of some quirks surrounding origin trials and content security
+// policies.
 class SystemWebAppManagerLaunchDirectoryBrowserTest
     : public SystemWebAppManagerFileHandlingBrowserTestBase {
  public:
@@ -654,10 +658,6 @@
   }
 };
 
-// Launching behavior for apps that do not want to received launch directory are
-// tested in |SystemWebAppManagerBrowserTestBase.LaunchFilesForSystemWebApp|.
-// Note: This test uses ExecuteScriptXXX instead of ExecJs and EvalJs because of
-// some quirks surrounding origin trials and content security policies.
 IN_PROC_BROWSER_TEST_P(SystemWebAppManagerLaunchDirectoryBrowserTest,
                        LaunchDirectoryForSystemWebApp) {
   WaitForTestSystemAppInstall();
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 5a7d02d..f4d3270 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -168,6 +168,8 @@
         "$root_gen_dir/chrome/cellular_setup_resources.pak",
         "$root_gen_dir/chrome/multidevice_internals_resources.pak",
         "$root_gen_dir/chrome/multidevice_setup_resources.pak",
+        "$root_gen_dir/chrome/nearby_shared_resources.pak",
+        "$root_gen_dir/chrome/nearby_shared_resources_v3.pak",
         "$root_gen_dir/chrome/os_settings_resources.pak",
         "$root_gen_dir/chromeos/chromeos_camera_app_resources.pak",
         "$root_gen_dir/chromeos/chromeos_help_app_bundle_resources.pak",
@@ -184,6 +186,8 @@
         "//ash/public/cpp/resources:ash_public_unscaled_resources",
         "//chrome/browser/resources:bluetooth_pairing_dialog_resources",
         "//chrome/browser/resources:multidevice_internals_resources",
+        "//chrome/browser/resources:nearby_shared_resources",
+        "//chrome/browser/resources:nearby_shared_resources_v3",
         "//chrome/browser/resources:os_settings_resources",
         "//chrome/browser/resources/chromeos:cellular_setup_resources",
         "//chrome/browser/resources/chromeos:multidevice_setup_resources",
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index e1108d6..07373ae 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -820,6 +820,10 @@
 };
 
 #if defined(OS_CHROMEOS)
+// Populates storage dimensions in UMA log if enabled. Requires diagnostics
+// package in the image.
+const base::Feature kUmaStorageDimensions{"UmaStorageDimensions",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
 // Allow a Wilco DTC (diagnostics and telemetry controller) on Chrome OS.
 // More info about the project may be found here:
 // https://docs.google.com/document/d/18Ijj8YlC8Q3EWRzLspIi2dGxg4vIBVe5sJgMPt9SWYo
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index b4d96a7..f910948 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -551,6 +551,8 @@
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWebUIDarkMode;
 
 #if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUmaStorageDimensions;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWilcoDtc;
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/chrome/credential_provider/common/gcp_strings.cc b/chrome/credential_provider/common/gcp_strings.cc
index 4e09175..f75def7fb 100644
--- a/chrome/credential_provider/common/gcp_strings.cc
+++ b/chrome/credential_provider/common/gcp_strings.cc
@@ -54,6 +54,8 @@
 const wchar_t kRegUninstallStringField[] = L"UninstallString";
 const wchar_t kRegUninstallArgumentsField[] = L"UninstallArguments";
 const wchar_t kRegUsageStatsName[] = L"usagestats";
+const wchar_t kRegUpdateTracksName[] = L"ap";
+const wchar_t kRegVersionName[] = L"pv";
 
 // Chrome is being opened to show the credential provider logon page.  This
 // page is always shown in incognito mode.
diff --git a/chrome/credential_provider/common/gcp_strings.h b/chrome/credential_provider/common/gcp_strings.h
index 0228e5d..ced5420d 100644
--- a/chrome/credential_provider/common/gcp_strings.h
+++ b/chrome/credential_provider/common/gcp_strings.h
@@ -78,6 +78,8 @@
 extern const wchar_t kRegUninstallStringField[];
 extern const wchar_t kRegUninstallArgumentsField[];
 extern const wchar_t kRegUsageStatsName[];
+extern const wchar_t kRegUpdateTracksName[];
+extern const wchar_t kRegVersionName[];
 
 // These are command line switches passed to chrome to start it as a process
 // used as a logon stub.
diff --git a/chrome/credential_provider/gaiacp/device_policies_manager.cc b/chrome/credential_provider/gaiacp/device_policies_manager.cc
index 61dc9e8f..e089b66 100644
--- a/chrome/credential_provider/gaiacp/device_policies_manager.cc
+++ b/chrome/credential_provider/gaiacp/device_policies_manager.cc
@@ -11,6 +11,8 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/win/registry.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
@@ -23,6 +25,12 @@
 #include "chrome/credential_provider/gaiacp/user_policies_manager.h"
 #include "chrome/credential_provider/gaiacp/win_http_url_fetcher.h"
 
+namespace {
+// Character used to separate the update channel and version components in the
+// update tracks value.
+const wchar_t kChannelAndVersionSeparator[] = L"-";
+}  // namespace
+
 namespace credential_provider {
 
 // static
@@ -82,4 +90,81 @@
   }
 }
 
+void DevicePoliciesManager::EnforceGcpwUpdatePolicy() {
+  // Apply the Omaha update policy.
+  DevicePolicies device_policies;
+  GetDevicePolicies(&device_policies);
+
+  base::win::RegKey key;
+  LONG status = key.Create(HKEY_LOCAL_MACHINE, kRegUpdaterClientStateAppPath,
+                           KEY_READ | KEY_SET_VALUE | KEY_WOW64_32KEY);
+  if (status != ERROR_SUCCESS) {
+    LOGFN(ERROR) << "Unable to open omaha key=" << kRegUpdaterClientStateAppPath
+                 << " status=" << status;
+    return;
+  }
+
+  base::string16 update_channel;  // Empty value indicates the stable channel.
+  std::wstring ap_value;
+  status = key.ReadValue(kRegUpdateTracksName, &ap_value);
+  GcpwVersion current_pinned_version(base::UTF16ToUTF8(ap_value));
+
+  if (status == ERROR_SUCCESS && !current_pinned_version.IsValid()) {
+    std::vector<base::string16> ap_components =
+        base::SplitString(ap_value, kChannelAndVersionSeparator,
+                          base::WhitespaceHandling::TRIM_WHITESPACE,
+                          base::SplitResult::SPLIT_WANT_NONEMPTY);
+    if (ap_components.size() > 0)
+      update_channel = ap_components[0];
+  }
+
+  if (device_policies.enable_gcpw_auto_update &&
+      !device_policies.gcpw_pinned_version.IsValid()) {
+    // Auto update enabled with no pinning so if installation was previously
+    // pinned to a version, remove the registry entry if device was on the
+    // stable channel or restore the previous channel.
+
+    if (update_channel.empty()) {
+      status = key.DeleteValue(kRegUpdateTracksName);
+      if (status != ERROR_SUCCESS) {
+        LOGFN(ERROR) << "Unable to delete " << kRegUpdateTracksName
+                     << " value status=" << status;
+      }
+    } else if (update_channel != ap_value) {
+      status = key.WriteValue(kRegUpdateTracksName, update_channel.c_str());
+      if (status != ERROR_SUCCESS) {
+        LOGFN(ERROR) << "Unable to reset " << kRegUpdateTracksName
+                     << " value to " << update_channel << ". status=" << status;
+      }
+    }
+  } else {
+    base::string16 gcpw_version;
+    if (device_policies.enable_gcpw_auto_update &&
+        device_policies.gcpw_pinned_version.IsValid()) {
+      // Auto update enabled with pinning so set it to the pinned track.
+      gcpw_version =
+          base::UTF8ToUTF16(device_policies.gcpw_pinned_version.ToString());
+    } else {
+      // Auto update is disabled so make sure we stay on the installed
+      // version.
+      GcpwVersion version = GcpwVersion::GetCurrentVersion();
+      if (!version.IsValid()) {
+        LOGFN(ERROR) << "Could not read currently installed version";
+        return;
+      }
+      gcpw_version = base::UTF8ToUTF16(version.ToString());
+    }
+
+    base::string16 ap_value = gcpw_version;
+    if (!update_channel.empty())
+      ap_value = update_channel + kChannelAndVersionSeparator + gcpw_version;
+
+    status = key.WriteValue(kRegUpdateTracksName, ap_value.c_str());
+    if (status != ERROR_SUCCESS) {
+      LOGFN(ERROR) << "Unable to write " << kRegUpdateTracksName
+                   << " value status=" << status;
+    }
+  }
+}
+
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/device_policies_manager.h b/chrome/credential_provider/gaiacp/device_policies_manager.h
index 882ae5b..2efa55f4 100644
--- a/chrome/credential_provider/gaiacp/device_policies_manager.h
+++ b/chrome/credential_provider/gaiacp/device_policies_manager.h
@@ -22,6 +22,9 @@
   // policies of all the existing users on the device.
   virtual void GetDevicePolicies(DevicePolicies* device_policies);
 
+  // Make sure GCPW update is set up correctly.
+  void EnforceGcpwUpdatePolicy();
+
  protected:
   // Returns the storage used for the instance pointer.
   static DevicePoliciesManager** GetInstanceStorage();
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 21c6e5b..ccf266f 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -38,6 +38,7 @@
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
 #include "chrome/credential_provider/gaiacp/auth_utils.h"
+#include "chrome/credential_provider/gaiacp/device_policies_manager.h"
 #include "chrome/credential_provider/gaiacp/event_logs_upload_manager.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
@@ -2082,6 +2083,11 @@
       LOGFN(ERROR) << "EnrollToGoogleMdmIfNeeded hr=" << putHR(hr);
   }
 
+  // Ensure GCPW gets updated to the correct version.
+  if (DevicePoliciesManager::Get()->CloudPoliciesEnabled()) {
+    DevicePoliciesManager::Get()->EnforceGcpwUpdatePolicy();
+  }
+
   // TODO(crbug.com/976744): Use the down scoped kKeyMdmAccessToken instead
   // of login scoped token.
   std::string access_token = GetDictStringUTF8(properties, kKeyAccessToken);
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
index f21bfc5a..4a3b182 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittests.cc
@@ -3311,5 +3311,140 @@
                                             ::testing::Bool(),
                                             ::testing::Bool()));
 
+// Test that correct Omaha update tracks are set when auto update policies are
+// defined.
+// Parameters are:
+// 1. bool   : Whether cloud policies feature is enabled.
+// 2. bool   : Whether GCPW auto update policy is enabled.
+// 3. string : GCPW pinned version policy set through the cloud policy.
+// 4. string : Existing update channel (Ex. 'beta') specified in the Omaha
+//             update track registry entry for GCPW application. Empty value
+//             is stable channel.
+// 5. string : Current value of GCPW pinned version.
+class GcpGaiaCredentialBaseOmahaUpdatePolicyTest
+    : public GcpGaiaCredentialBaseTest,
+      public ::testing::WithParamInterface<std::tuple<bool,
+                                                      bool,
+                                                      const wchar_t*,
+                                                      const wchar_t*,
+                                                      const wchar_t*>> {};
+
+TEST_P(GcpGaiaCredentialBaseOmahaUpdatePolicyTest, EnforceUpdatePolicy) {
+  bool cloud_policies_enabled = std::get<0>(GetParam());
+  bool enable_gcpw_auto_update = std::get<1>(GetParam());
+  base::string16 gcpw_pinned_version(std::get<2>(GetParam()));
+  base::string16 update_channel(std::get<3>(GetParam()));
+  base::string16 current_pinned_version(std::get<4>(GetParam()));
+
+  FakeDevicePoliciesManager fake_device_policies_manager(
+      cloud_policies_enabled);
+
+  DevicePolicies device_policies;
+  device_policies.enable_gcpw_auto_update = enable_gcpw_auto_update;
+  device_policies.gcpw_pinned_version =
+      GcpwVersion(base::UTF16ToUTF8(gcpw_pinned_version));
+  fake_device_policies_manager.SetDevicePolicies(device_policies);
+
+  const base::string16 current_gcpw_version(L"80.1.422.2");
+
+  // Add expected Omaha registry paths
+  base::win::RegKey clientsKey, clientsStateKey;
+  EXPECT_EQ(ERROR_SUCCESS,
+            clientsKey.Create(HKEY_LOCAL_MACHINE, kRegUpdaterClientsAppPath,
+                              KEY_SET_VALUE | KEY_WOW64_32KEY));
+  EXPECT_EQ(ERROR_SUCCESS, clientsKey.WriteValue(kRegVersionName,
+                                                 current_gcpw_version.c_str()));
+  EXPECT_EQ(
+      ERROR_SUCCESS,
+      clientsStateKey.Create(HKEY_LOCAL_MACHINE, kRegUpdaterClientStateAppPath,
+                             KEY_SET_VALUE | KEY_WOW64_32KEY));
+
+  // Set existing update tracks including the currently pinned version.
+  base::string16 current_update_track = current_pinned_version;
+  if (!update_channel.empty())
+    current_update_track = update_channel + L"-" + current_pinned_version;
+
+  if (!current_update_track.empty()) {
+    EXPECT_EQ(ERROR_SUCCESS,
+              clientsStateKey.WriteValue(kRegUpdateTracksName,
+                                         current_update_track.c_str()));
+  }
+
+  // Create a fake user associated to a gaia id.
+  CComBSTR sid;
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                kDefaultUsername, L"password", L"Full Name", L"comment",
+                base::UTF8ToUTF16(kDefaultGaiaId), base::string16(), &sid));
+
+  // Change token response to an valid one.
+  SetDefaultTokenHandleResponse(kDefaultValidTokenHandleResponse);
+
+  // Create provider and start logon.
+  Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
+
+  ASSERT_EQ(S_OK, InitializeProviderAndGetCredential(0, &cred));
+
+  ASSERT_EQ(S_OK, StartLogonProcessAndWait());
+
+  // Finish logon successfully.
+  ASSERT_EQ(S_OK, FinishLogonProcess(true, true, 0));
+
+  ASSERT_EQ(S_OK, ReleaseProvider());
+
+  base::win::RegKey key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, kRegUpdaterClientStateAppPath,
+                     KEY_READ | KEY_WOW64_32KEY));
+
+  std::wstring update_track_value;
+  LONG status = key.ReadValue(kRegUpdateTracksName, &update_track_value);
+
+  if (cloud_policies_enabled) {
+    if (device_policies.enable_gcpw_auto_update) {
+      if (device_policies.gcpw_pinned_version.IsValid()) {
+        // Check if pinned version is set.
+        ASSERT_EQ(ERROR_SUCCESS, status);
+        base::string16 expected_ap_value = gcpw_pinned_version;
+        if (!update_channel.empty())
+          expected_ap_value = update_channel + L"-" + gcpw_pinned_version;
+        ASSERT_EQ(expected_ap_value, update_track_value);
+      } else {
+        // Update track should be reset to the channel it was on before.
+        if (update_channel.empty()) {
+          ASSERT_NE(ERROR_SUCCESS, status);
+        } else {
+          ASSERT_EQ(ERROR_SUCCESS, status);
+          ASSERT_EQ(update_channel, update_track_value);
+        }
+      }
+    } else {
+      // Auto update is turned off.
+      ASSERT_EQ(ERROR_SUCCESS, status);
+      base::string16 expected_ap_value = current_gcpw_version;
+      if (!update_channel.empty())
+        expected_ap_value = update_channel + L"-" + current_gcpw_version;
+      ASSERT_EQ(expected_ap_value, update_track_value);
+    }
+  } else {
+    // There should be no change to existing update tracks.
+    if (current_update_track.empty()) {
+      ASSERT_NE(ERROR_SUCCESS, status);
+    } else {
+      ASSERT_EQ(ERROR_SUCCESS, status);
+      ASSERT_EQ(current_update_track, update_track_value);
+    }
+  }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    All,
+    GcpGaiaCredentialBaseOmahaUpdatePolicyTest,
+    ::testing::Combine(::testing::Bool(),
+                       ::testing::Bool(),
+                       ::testing::Values(L"", L"81.1.33.42"),
+                       ::testing::Values(L"", L"beta"),
+                       ::testing::Values(L"", L"80.2.35.4")));
+
 }  // namespace testing
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcpw_version.cc b/chrome/credential_provider/gaiacp/gcpw_version.cc
index badf472..0f5b621d 100644
--- a/chrome/credential_provider/gaiacp/gcpw_version.cc
+++ b/chrome/credential_provider/gaiacp/gcpw_version.cc
@@ -7,6 +7,10 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "chrome/credential_provider/common/gcp_strings.h"
+#include "chrome/credential_provider/gaiacp/logging.h"
 
 namespace credential_provider {
 
@@ -21,8 +25,10 @@
       base::SplitResult::SPLIT_WANT_NONEMPTY);
   for (size_t i = 0; i < std::min(version_.size(), components.size()); ++i) {
     unsigned value;
-    if (base::StringToUint(components[i], &value))
-      version_[i] = value;
+    if (!base::StringToUint(components[i], &value))
+      break;
+
+    version_[i] = value;
   }
 }
 
@@ -69,4 +75,24 @@
   return false;
 }
 
+bool GcpwVersion::IsValid() const {
+  return !(*this == GcpwVersion());
+}
+
+// static
+GcpwVersion GcpwVersion::GetCurrentVersion() {
+  base::win::RegKey key;
+  LONG status = key.Create(HKEY_LOCAL_MACHINE, kRegUpdaterClientsAppPath,
+                           KEY_READ | KEY_WOW64_32KEY);
+  if (status == ERROR_SUCCESS) {
+    std::wstring version_wstr;
+    status = key.ReadValue(kRegVersionName, &version_wstr);
+    if (status == ERROR_SUCCESS)
+      return GcpwVersion(base::WideToUTF8(version_wstr));
+  }
+
+  LOGFN(ERROR) << "Unable to read version from omaha key="
+               << kRegUpdaterClientsAppPath << " status=" << status;
+  return GcpwVersion();
+}
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/gaiacp/gcpw_version.h b/chrome/credential_provider/gaiacp/gcpw_version.h
index 9f05582..5e04c391 100644
--- a/chrome/credential_provider/gaiacp/gcpw_version.h
+++ b/chrome/credential_provider/gaiacp/gcpw_version.h
@@ -13,7 +13,7 @@
 // A structure to hold the version of GCPW.
 class GcpwVersion {
  public:
-  // Create a default with the current GCPW version.
+  // Create a default version which is not valid.
   GcpwVersion();
 
   // Construct using the given version string specified in
@@ -23,6 +23,9 @@
   // Copy constructor.
   GcpwVersion(const GcpwVersion& other);
 
+  // Gets the installed version of the GCPW client on this device.
+  static GcpwVersion GetCurrentVersion();
+
   // Returns a formatted string.
   std::string ToString() const;
 
@@ -46,6 +49,9 @@
   // Returns true when this version is less than |other| version.
   bool operator<(const GcpwVersion& other) const;
 
+  // Returns true if this is a valid version.
+  bool IsValid() const;
+
  private:
   std::array<unsigned, 4> version_;
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 8e989399..7bd048c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1448,7 +1448,6 @@
       "../browser/ui/webui/management_a11y_browsertest.cc",
       "../browser/ui/webui/management_a11y_browsertest.h",
       "../browser/ui/webui/management_ui_browsertest.cc",
-      "../browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc",
       "../browser/ui/webui/net_internals/net_internals_ui_browsertest.cc",
       "../browser/ui/webui/net_internals/net_internals_ui_browsertest.h",
       "../browser/ui/webui/new_tab_page/webui_ntp_browsertest.cc",
@@ -1614,6 +1613,7 @@
         "../browser/policy/system_features_policy_browsertest.cc",
         "../browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc",
         "../browser/ui/ash/holding_space/holding_space_client_impl_browsertest.cc",
+        "../browser/ui/webui/nearby_share/nearby_share_dialog_ui_browsertest.cc",
       ]
     }
 
@@ -3316,6 +3316,7 @@
     "../browser/language/url_language_histogram_factory_unittest.cc",
     "../browser/lite_video/lite_video_decider_unittest.cc",
     "../browser/lite_video/lite_video_hint_cache_unittest.cc",
+    "../browser/lite_video/lite_video_hint_unittest.cc",
     "../browser/lite_video/lite_video_user_blocklist_unittest.cc",
     "../browser/logging_chrome_unittest.cc",
     "../browser/mac/exception_processor_unittest.mm",
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 568a233..b1c5224 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -323,8 +323,6 @@
       "media/media_engagement_browsertest.js",
       "media/media_feeds_webui_browsertest.js",
       "media/media_history_webui_browsertest.js",
-      "nearby_share/nearby_browsertest.js",
-      "nearby_share/shared/nearby_shared_v3_browsertest.js",
       "new_tab_page/new_tab_page_browsertest.js",
       "usb_internals_browsertest.js",
     ]
@@ -343,6 +341,8 @@
         "chromeos/print_management/print_management_browsertest.js",
         "chromeos/scanning/scanning_app_browsertest.js",
         "multidevice_setup/multidevice_setup_browsertest.js",
+        "nearby_share/nearby_browsertest.js",
+        "nearby_share/shared/nearby_shared_v3_browsertest.js",
       ]
       deps += [ "//chromeos/services/machine_learning/public/cpp:test_support" ]
     }
diff --git a/chrome/test/data/webui/array_data_model_test.html b/chrome/test/data/webui/array_data_model_test.html
index 0b41f853..cbcdada 100644
--- a/chrome/test/data/webui/array_data_model_test.html
+++ b/chrome/test/data/webui/array_data_model_test.html
@@ -1,105 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body>
-
-<script>
-
-function testSlice() {
-  var m = new cr.ui.ArrayDataModel([0, 1, 2]);
-  assertArrayEquals([0, 1, 2], m.slice());
-  assertArrayEquals([1, 2], m.slice(1));
-  assertArrayEquals([1], m.slice(1, 2));
-}
-
-function testPush() {
-  var m = new cr.ui.ArrayDataModel([0, 1, 2]);
-
-  var count = 0;
-  m.addEventListener('splice', function(e) {
-    count++;
-    assertEquals(3, e.index);
-    assertArrayEquals([], e.removed);
-    assertArrayEquals([3, 4], e.added);
-  });
-
-  assertEquals(5, m.push(3, 4));
-  var a = m.slice();
-  assertArrayEquals([0, 1, 2, 3, 4], a);
-
-  assertEquals(1, count, 'The splice event should only fire once');
-}
-
-function testSplice() {
-  function compare(array, args) {
-    var m = new cr.ui.ArrayDataModel(array.slice());
-    var expected = array.slice();
-    var result = expected.splice.apply(expected, args);
-    assertArrayEquals(result, m.splice.apply(m, args));
-    assertArrayEquals(expected, m.slice());
-  }
-
-  compare([1, 2, 3], []);
-  compare([1, 2, 3], [0, 0]);
-  compare([1, 2, 3], [0, 1]);
-  compare([1, 2, 3], [1, 1]);
-  compare([1, 2, 3], [0, 3]);
-  compare([1, 2, 3], [0, 1, 5]);
-  compare([1, 2, 3], [0, 3, 1, 2, 3]);
-  compare([1, 2, 3], [5, 3, 1, 2, 3]);
-}
-
-function testPermutation() {
-  function doTest(sourceArray, spliceArgs) {
-    var m = new cr.ui.ArrayDataModel(sourceArray.slice());
-    var permutation;
-    m.addEventListener('permuted', function(event) {
-      permutation = event.permutation;
-    });
-    m.splice.apply(m, spliceArgs);
-    var deleted = 0;
-    for (var i = 0; i < sourceArray.length; i++) {
-      if (permutation[i] == -1)
-        deleted++;
-      else
-        assertEquals(sourceArray[i], m.item(permutation[i]));
-    }
-    assertEquals(deleted, spliceArgs[1]);
-  }
-
-  doTest([1, 2, 3], [0, 0]);
-  doTest([1, 2, 3], [0, 1]);
-  doTest([1, 2, 3], [1, 1]);
-  doTest([1, 2, 3], [0, 3]);
-  doTest([1, 2, 3], [0, 1, 5]);
-  doTest([1, 2, 3], [0, 3, 1, 2, 3]);
-}
-
-function testUpdateIndexes() {
-  var m = new cr.ui.ArrayDataModel([1, 2, 3]);
-  var changedIndexes = [];
-  m.addEventListener('change', function(event) {
-    changedIndexes.push(event.index);
-  });
-  m.updateIndexes([0, 1, 2]);
-  assertArrayEquals([0, 1, 2], changedIndexes);
-}
-
-function testReplaceItem() {
-  var m = new cr.ui.ArrayDataModel([1, 2, 3]);
-  var permutation = null;
-  var changeIndex;
-  m.addEventListener('permuted', function(event) {
-    permutation = event.permutation;
-  });
-  m.addEventListener('change', function(event) {
-    changeIndex = event.index;
-  });
-  m.replaceItem(2, 4);
-  assertEquals(null, permutation);
-  assertEquals(1, changeIndex);
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+<script src="array_data_model_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/array_data_model_test.js b/chrome/test/data/webui/array_data_model_test.js
new file mode 100644
index 0000000..eaa3087
--- /dev/null
+++ b/chrome/test/data/webui/array_data_model_test.js
@@ -0,0 +1,99 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testSlice() {
+  var m = new cr.ui.ArrayDataModel([0, 1, 2]);
+  assertArrayEquals([0, 1, 2], m.slice());
+  assertArrayEquals([1, 2], m.slice(1));
+  assertArrayEquals([1], m.slice(1, 2));
+}
+
+function testPush() {
+  var m = new cr.ui.ArrayDataModel([0, 1, 2]);
+
+  var count = 0;
+  m.addEventListener('splice', function(e) {
+    count++;
+    assertEquals(3, e.index);
+    assertArrayEquals([], e.removed);
+    assertArrayEquals([3, 4], e.added);
+  });
+
+  assertEquals(5, m.push(3, 4));
+  var a = m.slice();
+  assertArrayEquals([0, 1, 2, 3, 4], a);
+
+  assertEquals(1, count, 'The splice event should only fire once');
+}
+
+function testSplice() {
+  function compare(array, args) {
+    var m = new cr.ui.ArrayDataModel(array.slice());
+    var expected = array.slice();
+    var result = expected.splice.apply(expected, args);
+    assertArrayEquals(result, m.splice.apply(m, args));
+    assertArrayEquals(expected, m.slice());
+  }
+
+  compare([1, 2, 3], []);
+  compare([1, 2, 3], [0, 0]);
+  compare([1, 2, 3], [0, 1]);
+  compare([1, 2, 3], [1, 1]);
+  compare([1, 2, 3], [0, 3]);
+  compare([1, 2, 3], [0, 1, 5]);
+  compare([1, 2, 3], [0, 3, 1, 2, 3]);
+  compare([1, 2, 3], [5, 3, 1, 2, 3]);
+}
+
+function testPermutation() {
+  function doTest(sourceArray, spliceArgs) {
+    var m = new cr.ui.ArrayDataModel(sourceArray.slice());
+    var permutation;
+    m.addEventListener('permuted', function(event) {
+      permutation = event.permutation;
+    });
+    m.splice.apply(m, spliceArgs);
+    var deleted = 0;
+    for (var i = 0; i < sourceArray.length; i++) {
+      if (permutation[i] === -1) {
+        deleted++;
+      } else {
+        assertEquals(sourceArray[i], m.item(permutation[i]));
+      }
+    }
+    assertEquals(deleted, spliceArgs[1]);
+  }
+
+  doTest([1, 2, 3], [0, 0]);
+  doTest([1, 2, 3], [0, 1]);
+  doTest([1, 2, 3], [1, 1]);
+  doTest([1, 2, 3], [0, 3]);
+  doTest([1, 2, 3], [0, 1, 5]);
+  doTest([1, 2, 3], [0, 3, 1, 2, 3]);
+}
+
+function testUpdateIndexes() {
+  var m = new cr.ui.ArrayDataModel([1, 2, 3]);
+  var changedIndexes = [];
+  m.addEventListener('change', function(event) {
+    changedIndexes.push(event.index);
+  });
+  m.updateIndexes([0, 1, 2]);
+  assertArrayEquals([0, 1, 2], changedIndexes);
+}
+
+function testReplaceItem() {
+  var m = new cr.ui.ArrayDataModel([1, 2, 3]);
+  var permutation = null;
+  var changeIndex;
+  m.addEventListener('permuted', function(event) {
+    permutation = event.permutation;
+  });
+  m.addEventListener('change', function(event) {
+    changeIndex = event.index;
+  });
+  m.replaceItem(2, 4);
+  assertEquals(null, permutation);
+  assertEquals(1, changeIndex);
+}
diff --git a/chrome/test/data/webui/command_test.html b/chrome/test/data/webui/command_test.html
index dced9116..f199ceac 100644
--- a/chrome/test/data/webui/command_test.html
+++ b/chrome/test/data/webui/command_test.html
@@ -5,47 +5,11 @@
 </head>
 <body>
 <command shortcut="n|Ctrl"></command>
-<script>
-
-function testCommandDefaultPrevented() {
-  var calls = 0;
-  document.addEventListener('canExecute', function(e) {
-    ++calls;
-    assertFalse(e.defaultPrevented);
-    e.canExecute = true;
-    assertTrue(e.defaultPrevented);
-  });
-
-  cr.ui.decorate('command', cr.ui.Command);
-  document.querySelector('command').canExecuteChange();
-  assertEquals(1, calls);
-}
-
-function createEvent(key, code, keyCode) {
-  return {
-    key: key,
-    code: code,
-    keyCode: keyCode,
-    altKey: false,
-    ctrlKey: true,
-    metaKey: false,
-    shiftKey: false
-  };
-}
-
-function testShortcuts() {
-  cr.ui.decorate('command', cr.ui.Command);
-  const cmd = document.querySelector('command');
-  // US keyboard - qwerty-N should work.
-  assertTrue(cmd.matchesEvent(createEvent('n', 'KeyN', 0x4e)));
-  // DV keyboard - qwerty-L (dvorak-N) should work.
-  assertTrue(cmd.matchesEvent(createEvent('n', 'KeyL', 0x4e)));
-  // DV keyboard - qwerty-N (dvorak-B) should not work.
-  assertFalse(cmd.matchesEvent(createEvent('b', 'KeyN', 0x42)));
-  // RU keyboard - qwerty-N (Cyrillic Te) should work. 
-  assertTrue(cmd.matchesEvent(createEvent('Ñ‚', 'KeyN', 0x4e)));
-}
-
-</script>
+<script src="chrome://resources/js/assert.js"></script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/keyboard_shortcut_list.js"></script>
+<script src="chrome://resources/js/cr/ui/command.js"></script>
+<script src="command_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/command_test.js b/chrome/test/data/webui/command_test.js
new file mode 100644
index 0000000..5e52afa
--- /dev/null
+++ b/chrome/test/data/webui/command_test.js
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testCommandDefaultPrevented() {
+  var calls = 0;
+  document.addEventListener('canExecute', function(e) {
+    ++calls;
+    assertFalse(e.defaultPrevented);
+    e.canExecute = true;
+    assertTrue(e.defaultPrevented);
+  });
+
+  cr.ui.decorate('command', cr.ui.Command);
+  document.querySelector('command').canExecuteChange();
+  assertEquals(1, calls);
+}
+
+function createEvent(key, code, keyCode) {
+  return {
+    key: key,
+    code: code,
+    keyCode: keyCode,
+    altKey: false,
+    ctrlKey: true,
+    metaKey: false,
+    shiftKey: false
+  };
+}
+
+function testShortcuts() {
+  cr.ui.decorate('command', cr.ui.Command);
+  const cmd = document.querySelector('command');
+  // US keyboard - qwerty-N should work.
+  assertTrue(cmd.matchesEvent(createEvent('n', 'KeyN', 0x4e)));
+  // DV keyboard - qwerty-L (dvorak-N) should work.
+  assertTrue(cmd.matchesEvent(createEvent('n', 'KeyL', 0x4e)));
+  // DV keyboard - qwerty-N (dvorak-B) should not work.
+  assertFalse(cmd.matchesEvent(createEvent('b', 'KeyN', 0x42)));
+  // RU keyboard - qwerty-N (Cyrillic Te) should work.
+  assertTrue(cmd.matchesEvent(createEvent('Ñ‚', 'KeyN', 0x4e)));
+}
diff --git a/chrome/test/data/webui/context_menu_handler_test.html b/chrome/test/data/webui/context_menu_handler_test.html
index 366ed0e..9b55781 100644
--- a/chrome/test/data/webui/context_menu_handler_test.html
+++ b/chrome/test/data/webui/context_menu_handler_test.html
@@ -1,65 +1,16 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-function testShowAndHideEvents() {
-  // Keep original Date.now not to affect other code.
-  var originalDateNow = Date.now;
-
-  // Initial value is 1 since 0 becomes false.
-  var currentTime = 1;
-
-  // Overrides Date.now to simulate time.
-  Date.now = function() { return currentTime; };
-
-  var cmh = cr.ui.contextMenuHandler;
-
-  // Create context menu.
-  var menu = document.createElement('div');
-  cr.ui.decorate(menu, cr.ui.Menu);
-  document.body.appendChild(menu);
-
-  var menuItem = document.createElement('div');
-  menu.addMenuItem(menuItem);
-
-  // Create target elements.
-  var elem1 = document.createElement('div');
-  var elem2 = document.createElement('div');
-
-  cmh.setContextMenu(elem1, menu);
-  cmh.setContextMenu(elem2, menu);
-
-  var events = [];
-  cmh.addEventListener('show', function(e) { events.push(e); });
-  cmh.addEventListener('hide', function(e) { events.push(e); });
-
-  // Show context menu of elem1.
-  elem1.dispatchEvent(new MouseEvent('contextmenu'));
-  assertEquals(1, events.length);
-  assertEquals('show', events[0].type);
-  assertEquals(elem1, events[0].element);
-  assertEquals(menu, events[0].menu);
-
-  // Show context menu of elem2.
-  document.dispatchEvent(new MouseEvent('mousedown'));
-
-  // On Windows to prevent context menu show again by mouse right button up,
-  // we need to wait at least 50ms from the last hide of context menu.
-  currentTime += 51; // ms
-
-  elem2.dispatchEvent(new MouseEvent('contextmenu'));
-  assertEquals(3, events.length);
-  assertEquals('hide', events[1].type);
-  assertEquals(elem1, events[1].element);
-  assertEquals(menu, events[1].menu);
-  assertEquals('show', events[2].type);
-  assertEquals(elem2, events[2].element);
-  assertEquals(menu, events[2].menu);
-
-  Date.now = originalDateNow;
-}
-
-</script>
+<script src="chrome://resources/js/assert.js"></script>
+<script src="chrome://resources/js/event_tracker.js"></script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/position_util.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_item.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_button.js"></script>
+<script src="chrome://resources/js/cr/ui/menu.js"></script>
+<script src="chrome://resources/js/cr/ui/context_menu_handler.js"></script>
+<script src="context_menu_handler_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/context_menu_handler_test.js b/chrome/test/data/webui/context_menu_handler_test.js
new file mode 100644
index 0000000..e6122a7
--- /dev/null
+++ b/chrome/test/data/webui/context_menu_handler_test.js
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testShowAndHideEvents() {
+  // Keep original Date.now not to affect other code.
+  var originalDateNow = Date.now;
+
+  // Initial value is 1 since 0 becomes false.
+  var currentTime = 1;
+
+  // Overrides Date.now to simulate time.
+  Date.now = function() {
+    return currentTime;
+  };
+
+  var cmh = cr.ui.contextMenuHandler;
+
+  // Create context menu.
+  var menu = document.createElement('div');
+  cr.ui.decorate(menu, cr.ui.Menu);
+  document.body.appendChild(menu);
+
+  var menuItem = document.createElement('div');
+  menu.addMenuItem(menuItem);
+
+  // Create target elements.
+  var elem1 = document.createElement('div');
+  var elem2 = document.createElement('div');
+
+  cmh.setContextMenu(elem1, menu);
+  cmh.setContextMenu(elem2, menu);
+
+  var events = [];
+  cmh.addEventListener('show', function(e) {
+    events.push(e);
+  });
+  cmh.addEventListener('hide', function(e) {
+    events.push(e);
+  });
+
+  // Show context menu of elem1.
+  elem1.dispatchEvent(new MouseEvent('contextmenu'));
+  assertEquals(1, events.length);
+  assertEquals('show', events[0].type);
+  assertEquals(elem1, events[0].element);
+  assertEquals(menu, events[0].menu);
+
+  // Show context menu of elem2.
+  document.dispatchEvent(new MouseEvent('mousedown'));
+
+  // On Windows to prevent context menu show again by mouse right button up,
+  // we need to wait at least 50ms from the last hide of context menu.
+  currentTime += 51;  // ms
+
+  elem2.dispatchEvent(new MouseEvent('contextmenu'));
+  assertEquals(3, events.length);
+  assertEquals('hide', events[1].type);
+  assertEquals(elem1, events[1].element);
+  assertEquals(menu, events[1].menu);
+  assertEquals('show', events[2].type);
+  assertEquals(elem2, events[2].element);
+  assertEquals(menu, events[2].menu);
+
+  Date.now = originalDateNow;
+}
diff --git a/chrome/test/data/webui/cr_reload_test.html b/chrome/test/data/webui/cr_reload_test.html
index d3bb982..27215d9d 100644
--- a/chrome/test/data/webui/cr_reload_test.html
+++ b/chrome/test/data/webui/cr_reload_test.html
@@ -1,14 +1,11 @@
 <!DOCTYPE html>
 <html>
 <body>
-
-<script>
-
-function testCrUIStillExists() {
-  assertFalse(cr.ui == undefined);
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<!-- Loading cr.js again on purpose to check whether it overwrites the cr
+    namespace. -->
+<script src="chrome://resources/js/cr.js"></script>
+<script src="cr_reload_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/cr_reload_test.js b/chrome/test/data/webui/cr_reload_test.js
new file mode 100644
index 0000000..7b105aae
--- /dev/null
+++ b/chrome/test/data/webui/cr_reload_test.js
@@ -0,0 +1,7 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testCrUIStillExists() {
+  assertFalse(cr.ui === undefined);
+}
diff --git a/chrome/test/data/webui/cr_test.html b/chrome/test/data/webui/cr_test.html
index e15bbce..7d33b948 100644
--- a/chrome/test/data/webui/cr_test.html
+++ b/chrome/test/data/webui/cr_test.html
@@ -1,265 +1,8 @@
 <!DOCTYPE html>
 <html>
 <body>
-
-<script>
-
-var EventTarget;
-
-function setUp() {
-  EventTarget = cr.EventTarget;
-}
-
-function testDefineProperty() {
-  var obj = new EventTarget;
-  cr.defineProperty(obj, 'test');
-
-  obj.test = 1;
-  assertEquals(1, obj.test);
-  assertEquals(1, obj.test_);
-}
-
-function testDefinePropertyOnClass() {
-  class C extends EventTarget {}
-
-  cr.defineProperty(C, 'test');
-
-  var obj = new C;
-  assertEquals(undefined, obj.test);
-
-  obj.test = 1;
-  assertEquals(1, obj.test);
-  assertEquals(1, obj.test_);
-}
-
-function testDefinePropertyWithSetter() {
-  var obj = new EventTarget;
-
-  var hit = false;
-  function onTestSet(value, oldValue) {
-    assertEquals(obj, this);
-    assertEquals(2, this.test);
-    assertEquals(undefined, oldValue);
-    assertEquals(2, value);
-    hit = true;
-  }
-  cr.defineProperty(obj, 'test', cr.PropertyKind.JS, onTestSet); 
-  obj.test = 2;
-  assertTrue(hit);
-}
-
-function testDefinePropertyEvent() {
-  var obj = new EventTarget;
-  cr.defineProperty(obj, 'test');
-  obj.test = 1;
-
-  var count = 0;
-  function f(e) {
-    assertEquals('testChange', e.type);
-    assertEquals('test', e.propertyName);
-    assertEquals(1, e.oldValue);
-    assertEquals(2, e.newValue);
-    count++;
-  }
-
-  obj.addEventListener('testChange', f);
-  obj.test = 2;
-  assertEquals(2, obj.test);
-  assertEquals(1, count, 'Should have called the property change listener');
-
-  obj.test = 2;
-  assertEquals(1, count);
-}
-
-function testDefinePropertyEventWithDefault() {
-  var obj = new EventTarget;
-  cr.defineProperty(obj, 'test', cr.PropertyKind.JS);
-
-  var count = 0;
-  function f(e) {
-    assertEquals('testChange', e.type);
-    assertEquals('test', e.propertyName);
-    assertEquals(undefined, e.oldValue);
-    assertEquals(2, e.newValue);
-    count++;
-  }
-
-  obj.addEventListener('testChange', f);
-
-  obj.test = undefined;
-  assertEquals(0, count, 'Should not have called the property change listener');
-
-  obj.test = 2;
-  assertEquals(2, obj.test);
-  assertEquals(1, count, 'Should have called the property change listener');
-
-  obj.test = 2;
-  assertEquals(1, count);
-}
-
-function testDefinePropertyAttr() {
-  var obj = document.createElement('div');
-  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR);
-
-  obj.test = 'a';
-  assertEquals('a', obj.test);
-  assertEquals('a', obj.getAttribute('test'));
-
-  obj.test = undefined;
-  assertEquals(null, obj.test);
-  assertFalse(obj.hasAttribute('test'));
-}
-
-function testDefinePropertyAttrOnClass() {
-  var obj = document.createElement('button');
-  cr.defineProperty(HTMLButtonElement, 'test', cr.PropertyKind.ATTR);
-
-  assertEquals(null, obj.test);
-
-  obj.test = 'a';
-  assertEquals('a', obj.test);
-  assertEquals('a', obj.getAttribute('test'));
-
-  obj.test = undefined;
-  assertEquals(null, obj.test);
-  assertFalse(obj.hasAttribute('test'));
-}
-
-function testDefinePropertyAttrWithSetter() {
-  var obj = document.createElement('div');
-
-  var hit = false;
-  function onTestSet(value, oldValue) {
-    assertEquals(obj, this);
-    assertEquals(null, oldValue);
-    assertEquals('b', value);
-    assertEquals('b', this.test);
-    hit = true;
-  }
-  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR, onTestSet);
-  obj.test = 'b';
-  assertTrue(hit);
-}
-
-function testDefinePropertyAttrEvent() {
-  var obj = document.createElement('div');
-  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR);
-
-  var count = 0;
-  function f(e) {
-    assertEquals('testChange', e.type);
-    assertEquals('test', e.propertyName);
-    assertEquals(null, e.oldValue);
-    assertEquals('b', e.newValue);
-    count++;
-  }
-
-  obj.addEventListener('testChange', f);
-
-  obj.test = null;
-  assertEquals(0, count, 'Should not have called the property change listener');
-
-  obj.test = 'b';
-  assertEquals('b', obj.test);
-  assertEquals(1, count, 'Should have called the property change listener');
-
-  obj.test = 'b';
-  assertEquals(1, count);
-}
-
-function testDefinePropertyBoolAttr() {
-  var obj = document.createElement('div');
-  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR);
-
-  assertFalse(obj.test);
-  assertFalse(obj.hasAttribute('test'));
-
-  obj.test = true;
-  assertTrue(obj.test);
-  assertTrue(obj.hasAttribute('test'));
-
-  obj.test = false;
-  assertFalse(obj.test);
-  assertFalse(obj.hasAttribute('test'));
-}
-
-function testDefinePropertyBoolAttrEvent() {
-  var obj = document.createElement('div');
-  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR);
-
-  var count = 0;
-  function f(e) {
-    assertEquals('testChange', e.type);
-    assertEquals('test', e.propertyName);
-    assertEquals(false, e.oldValue);
-    assertEquals(true, e.newValue);
-    count++;
-  }
-
-  obj.addEventListener('testChange', f);
-  obj.test = true;
-  assertTrue(obj.test);
-  assertEquals(1, count, 'Should have called the property change listener');
-
-  obj.test = true;
-  assertEquals(1, count);
-}
-
-function testDefinePropertyBoolAttrEvent() {
-  var obj = document.createElement('div');
-  var hit = false;
-  function onTestSet(value, oldValue) {
-    assertEquals(obj, this);
-    assertTrue(this.test);
-    assertFalse(oldValue);
-    assertTrue(value);
-    hit = true;
-  }
-  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR, onTestSet);
-  obj.test = true;
-  assertTrue(hit);
-}
-
-function testAddSingletonGetter() {
-  function Foo() {};
-  cr.addSingletonGetter(Foo);
-
-  assertEquals('function', typeof Foo.getInstance,
-      'Should add get instance function');
-
-  var x = Foo.getInstance();
-  assertEquals('object', typeof x, 'Should successfully create an object');
-  assertNotEqual(null, x, 'Created object should not be null');
-
-  var y = Foo.getInstance();
-  assertEquals(x, y, 'Should return the same object');
-
-  delete Foo.instance_;
-
-  var z = Foo.getInstance();
-  assertEquals('object', typeof z, 'Should work after clearing for testing');
-  assertNotEqual(null, z, 'Created object should not be null');
-
-  assertNotEqual(x, z,
-      'Should return a different object after clearing for testing');
-}
-
-function testDefineWithGetter() {
-  var v = 0;
-  cr.define('foo', function() {
-    return {
-      get v() {
-        return v;
-      }
-    }
-  });
-
-  assertEquals(0, foo.v);
-
-  v = 1;
-  assertEquals(1, foo.v);
-}
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="cr_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/cr_test.js b/chrome/test/data/webui/cr_test.js
new file mode 100644
index 0000000..6a01e35e
--- /dev/null
+++ b/chrome/test/data/webui/cr_test.js
@@ -0,0 +1,259 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var EventTarget;
+
+function setUp() {
+  EventTarget = cr.EventTarget;
+}
+
+function testDefineProperty() {
+  var obj = new EventTarget;
+  cr.defineProperty(obj, 'test');
+
+  obj.test = 1;
+  assertEquals(1, obj.test);
+  assertEquals(1, obj.test_);
+}
+
+function testDefinePropertyOnClass() {
+  class C extends EventTarget {}
+
+  cr.defineProperty(C, 'test');
+
+  var obj = new C;
+  assertEquals(undefined, obj.test);
+
+  obj.test = 1;
+  assertEquals(1, obj.test);
+  assertEquals(1, obj.test_);
+}
+
+function testDefinePropertyWithSetter() {
+  var obj = new EventTarget;
+
+  var hit = false;
+  function onTestSet(value, oldValue) {
+    assertEquals(obj, this);
+    assertEquals(2, this.test);
+    assertEquals(undefined, oldValue);
+    assertEquals(2, value);
+    hit = true;
+  }
+  cr.defineProperty(obj, 'test', cr.PropertyKind.JS, onTestSet);
+  obj.test = 2;
+  assertTrue(hit);
+}
+
+function testDefinePropertyEvent() {
+  var obj = new EventTarget;
+  cr.defineProperty(obj, 'test');
+  obj.test = 1;
+
+  var count = 0;
+  function f(e) {
+    assertEquals('testChange', e.type);
+    assertEquals('test', e.propertyName);
+    assertEquals(1, e.oldValue);
+    assertEquals(2, e.newValue);
+    count++;
+  }
+
+  obj.addEventListener('testChange', f);
+  obj.test = 2;
+  assertEquals(2, obj.test);
+  assertEquals(1, count, 'Should have called the property change listener');
+
+  obj.test = 2;
+  assertEquals(1, count);
+}
+
+function testDefinePropertyEventWithDefault() {
+  var obj = new EventTarget;
+  cr.defineProperty(obj, 'test', cr.PropertyKind.JS);
+
+  var count = 0;
+  function f(e) {
+    assertEquals('testChange', e.type);
+    assertEquals('test', e.propertyName);
+    assertEquals(undefined, e.oldValue);
+    assertEquals(2, e.newValue);
+    count++;
+  }
+
+  obj.addEventListener('testChange', f);
+
+  obj.test = undefined;
+  assertEquals(0, count, 'Should not have called the property change listener');
+
+  obj.test = 2;
+  assertEquals(2, obj.test);
+  assertEquals(1, count, 'Should have called the property change listener');
+
+  obj.test = 2;
+  assertEquals(1, count);
+}
+
+function testDefinePropertyAttr() {
+  var obj = document.createElement('div');
+  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR);
+
+  obj.test = 'a';
+  assertEquals('a', obj.test);
+  assertEquals('a', obj.getAttribute('test'));
+
+  obj.test = undefined;
+  assertEquals(null, obj.test);
+  assertFalse(obj.hasAttribute('test'));
+}
+
+function testDefinePropertyAttrOnClass() {
+  var obj = document.createElement('button');
+  cr.defineProperty(HTMLButtonElement, 'test', cr.PropertyKind.ATTR);
+
+  assertEquals(null, obj.test);
+
+  obj.test = 'a';
+  assertEquals('a', obj.test);
+  assertEquals('a', obj.getAttribute('test'));
+
+  obj.test = undefined;
+  assertEquals(null, obj.test);
+  assertFalse(obj.hasAttribute('test'));
+}
+
+function testDefinePropertyAttrWithSetter() {
+  var obj = document.createElement('div');
+
+  var hit = false;
+  function onTestSet(value, oldValue) {
+    assertEquals(obj, this);
+    assertEquals(null, oldValue);
+    assertEquals('b', value);
+    assertEquals('b', this.test);
+    hit = true;
+  }
+  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR, onTestSet);
+  obj.test = 'b';
+  assertTrue(hit);
+}
+
+function testDefinePropertyAttrEvent() {
+  var obj = document.createElement('div');
+  cr.defineProperty(obj, 'test', cr.PropertyKind.ATTR);
+
+  var count = 0;
+  function f(e) {
+    assertEquals('testChange', e.type);
+    assertEquals('test', e.propertyName);
+    assertEquals(null, e.oldValue);
+    assertEquals('b', e.newValue);
+    count++;
+  }
+
+  obj.addEventListener('testChange', f);
+
+  obj.test = null;
+  assertEquals(0, count, 'Should not have called the property change listener');
+
+  obj.test = 'b';
+  assertEquals('b', obj.test);
+  assertEquals(1, count, 'Should have called the property change listener');
+
+  obj.test = 'b';
+  assertEquals(1, count);
+}
+
+function testDefinePropertyBoolAttr() {
+  var obj = document.createElement('div');
+  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR);
+
+  assertFalse(obj.test);
+  assertFalse(obj.hasAttribute('test'));
+
+  obj.test = true;
+  assertTrue(obj.test);
+  assertTrue(obj.hasAttribute('test'));
+
+  obj.test = false;
+  assertFalse(obj.test);
+  assertFalse(obj.hasAttribute('test'));
+}
+
+function testDefinePropertyBoolAttrEvent() {
+  var obj = document.createElement('div');
+  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR);
+
+  var count = 0;
+  function f(e) {
+    assertEquals('testChange', e.type);
+    assertEquals('test', e.propertyName);
+    assertEquals(false, e.oldValue);
+    assertEquals(true, e.newValue);
+    count++;
+  }
+
+  obj.addEventListener('testChange', f);
+  obj.test = true;
+  assertTrue(obj.test);
+  assertEquals(1, count, 'Should have called the property change listener');
+
+  obj.test = true;
+  assertEquals(1, count);
+}
+
+function testDefinePropertyBoolAttrEventWithHook() {
+  var obj = document.createElement('div');
+  var hit = false;
+  function onTestSet(value, oldValue) {
+    assertEquals(obj, this);
+    assertTrue(this.test);
+    assertFalse(oldValue);
+    assertTrue(value);
+    hit = true;
+  }
+  cr.defineProperty(obj, 'test', cr.PropertyKind.BOOL_ATTR, onTestSet);
+  obj.test = true;
+  assertTrue(hit);
+}
+
+function testAddSingletonGetter() {
+  function Foo() {}
+  cr.addSingletonGetter(Foo);
+
+  assertEquals(
+      'function', typeof Foo.getInstance, 'Should add get instance function');
+
+  var x = Foo.getInstance();
+  assertEquals('object', typeof x, 'Should successfully create an object');
+  assertNotEqual(null, x, 'Created object should not be null');
+
+  var y = Foo.getInstance();
+  assertEquals(x, y, 'Should return the same object');
+
+  delete Foo.instance_;
+
+  var z = Foo.getInstance();
+  assertEquals('object', typeof z, 'Should work after clearing for testing');
+  assertNotEqual(null, z, 'Created object should not be null');
+
+  assertNotEqual(
+      x, z, 'Should return a different object after clearing for testing');
+}
+
+function testDefineWithGetter() {
+  var v = 0;
+  cr.define('foo', function() {
+    return {
+      get v() {
+        return v;
+      }
+    };
+  });
+
+  assertEquals(0, foo.v);
+
+  v = 1;
+  assertEquals(1, foo.v);
+}
diff --git a/chrome/test/data/webui/event_target_test.html b/chrome/test/data/webui/event_target_test.html
index 514c96c..64238e53 100644
--- a/chrome/test/data/webui/event_target_test.html
+++ b/chrome/test/data/webui/event_target_test.html
@@ -1,101 +1,8 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-/* @const */ var EventTarget;
-
-function setUp(){
-  EventTarget = cr.EventTarget;
-}
-
-function testFunctionListener() {
-  var fi = 0;
-  function f(e) {
-    fi++;
-  }
-
-  var gi = 0;
-  function g(e) {
-    gi++;
-  }
-
-  var et = new EventTarget;
-  et.addEventListener('f', f);
-  et.addEventListener('g', g);
-
-  // Adding again should not cause it to be called twice
-  et.addEventListener('f', f);
-  et.dispatchEvent(new Event('f'));
-  assertEquals(1, fi, 'Should have been called once');
-  assertEquals(0, gi);
-
-  et.removeEventListener('f', f);
-  et.dispatchEvent(new Event('f'));
-  assertEquals(1, fi, 'Should not have been called again');
-
-  et.dispatchEvent(new Event('g'));
-  assertEquals(1, gi, 'Should have been called once');
-}
-
-function testHandleEvent() {
-  var fi = 0;
-  var f = {
-    handleEvent: function(e) {
-      fi++;
-    }
-  };
-
-  var gi = 0;
-  var g = {
-    handleEvent: function(e) {
-      gi++;
-    }
-  };
-
-  var et = new EventTarget;
-  et.addEventListener('f', f);
-  et.addEventListener('g', g);
-
-  // Adding again should not cause it to be called twice
-  et.addEventListener('f', f);
-  et.dispatchEvent(new Event('f'));
-  assertEquals(1, fi, 'Should have been called once');
-  assertEquals(0, gi);
-
-  et.removeEventListener('f', f);
-  et.dispatchEvent(new Event('f'));
-  assertEquals(1, fi, 'Should not have been called again');
-
-  et.dispatchEvent(new Event('g'));
-  assertEquals(1, gi, 'Should have been called once');
-}
-
-function testPreventDefault() {
-  var i = 0;
-  function prevent(e) {
-    i++;
-    e.preventDefault();
-  }
-
-  var j = 0;
-  function pass(e) {
-    j++;
-  }
-
-  var et = new EventTarget;
-  et.addEventListener('test', pass);
-
-  assertTrue(et.dispatchEvent(new Event('test', {cancelable: true})));
-  assertEquals(1, j);
-
-  et.addEventListener('test', prevent);
-
-  console.log('NOW');
-  assertFalse(et.dispatchEvent(new Event('test', {cancelable: true})));
-  assertEquals(2, j);
-  assertEquals(1, i);
-}
-</script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="event_target_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/event_target_test.js b/chrome/test/data/webui/event_target_test.js
new file mode 100644
index 0000000..31e97df
--- /dev/null
+++ b/chrome/test/data/webui/event_target_test.js
@@ -0,0 +1,97 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* @const */ var EventTarget;
+
+function setUp() {
+  EventTarget = cr.EventTarget;
+}
+
+function testFunctionListener() {
+  var fi = 0;
+  function f(e) {
+    fi++;
+  }
+
+  var gi = 0;
+  function g(e) {
+    gi++;
+  }
+
+  var et = new EventTarget;
+  et.addEventListener('f', f);
+  et.addEventListener('g', g);
+
+  // Adding again should not cause it to be called twice
+  et.addEventListener('f', f);
+  et.dispatchEvent(new Event('f'));
+  assertEquals(1, fi, 'Should have been called once');
+  assertEquals(0, gi);
+
+  et.removeEventListener('f', f);
+  et.dispatchEvent(new Event('f'));
+  assertEquals(1, fi, 'Should not have been called again');
+
+  et.dispatchEvent(new Event('g'));
+  assertEquals(1, gi, 'Should have been called once');
+}
+
+function testHandleEvent() {
+  var fi = 0;
+  var f = {
+    handleEvent: function(e) {
+      fi++;
+    }
+  };
+
+  var gi = 0;
+  var g = {
+    handleEvent: function(e) {
+      gi++;
+    }
+  };
+
+  var et = new EventTarget;
+  et.addEventListener('f', f);
+  et.addEventListener('g', g);
+
+  // Adding again should not cause it to be called twice
+  et.addEventListener('f', f);
+  et.dispatchEvent(new Event('f'));
+  assertEquals(1, fi, 'Should have been called once');
+  assertEquals(0, gi);
+
+  et.removeEventListener('f', f);
+  et.dispatchEvent(new Event('f'));
+  assertEquals(1, fi, 'Should not have been called again');
+
+  et.dispatchEvent(new Event('g'));
+  assertEquals(1, gi, 'Should have been called once');
+}
+
+function testPreventDefault() {
+  var i = 0;
+  function prevent(e) {
+    i++;
+    e.preventDefault();
+  }
+
+  var j = 0;
+  function pass(e) {
+    j++;
+  }
+
+  var et = new EventTarget;
+  et.addEventListener('test', pass);
+
+  assertTrue(et.dispatchEvent(new Event('test', {cancelable: true})));
+  assertEquals(1, j);
+
+  et.addEventListener('test', prevent);
+
+  console.log('NOW');
+  assertFalse(et.dispatchEvent(new Event('test', {cancelable: true})));
+  assertEquals(2, j);
+  assertEquals(1, i);
+}
diff --git a/chrome/test/data/webui/grid_test.html b/chrome/test/data/webui/grid_test.html
index 889af63..910a33d2 100644
--- a/chrome/test/data/webui/grid_test.html
+++ b/chrome/test/data/webui/grid_test.html
@@ -1,87 +1,15 @@
 <!DOCTYPE html>
 <html>
 <body>
-
-<script>
-
-function testGetColumnCount() {
-  var g = cr.ui.Grid.prototype;
-  g.measured_ = {
-      height: 8,
-      marginTop: 0,
-      marginBottom: 0,
-      width: 10,
-      marginLeft: 0,
-      marginRight: 0
-  };
-  var columns = g.getColumnCount_();
-  g.measured_.width = 0;
-  columns = g.getColumnCount_();
-  // Item width equals 0.
-  assertEquals(0, columns);
-
-  g.measured_.width = 10;
-  columns = g.getColumnCount_();
-  // No item in the list.
-  assertEquals(0, columns);
-
-  g.dataModel_ = new cr.ui.ArrayDataModel([0, 1, 2]);
-  g.horizontalPadding_ = 0;
-  g.clientWidthWithoutScrollbar_ = 8;
-  columns = g.getColumnCount_();
-  // Client width is smaller than item width.
-  assertEquals(0, columns);
-
-  g.clientWidthWithoutScrollbar_ = 20;
-  // Client height can fit two rows.
-  g.clientHeight_ = 16;
-  columns = g.getColumnCount_();
-  assertEquals(2, columns);
-
-  // Client height can not fit two rows. A scroll bar is needed.
-  g.clientHeight_ = 15;
-  g.clientWidthWithScrollbar_ = 18;
-  columns = g.getColumnCount_();
-  // Can not fit two columns due to the scroll bar.
-  assertEquals(1, columns);
-
-  g.clientHeight_ = 16;
-  g.measured_.marginTop = 1;
-  columns = g.getColumnCount_();
-  // Can fit two columns due to uncollapse margin.
-  assertEquals(2, columns);
-
-  g.measured_.marginBottom = 1;
-  columns = g.getColumnCount_();
-  // Can not fit two columns due to margin.
-  assertEquals(1, columns);
-
-  g.measured_.marginTop = 0;
-  g.measured_.marginBottom = 0;
-  g.measured_.marginLeft = 1;
-  columns = g.getColumnCount_();
-  // Can fit two columns due to uncollapse margin.
-  assertEquals(2, columns);
-
-  g.measured_.marginRight = 1;
-  columns = g.getColumnCount_();
-  // Can not fit two columns due to margin on left and right side.
-  assertEquals(1, columns);
-
-  g.measured_.marginRight = 0;
-  g.horizontalPadding_ = 2;
-  g.clientWidthWithoutScrollbar_ = 22;
-  columns = g.getColumnCount_();
-  // Can fit two columns as (22-2=)20px width is avaiable for grid items.
-  assertEquals(2, columns);
-
-  g.horizontalPadding_ = 3;
-  columns = g.getColumnCount_();
-  // Can not fit two columns due to bigger horizontal padding.
-  assertEquals(1, columns);
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list.js"></script>
+<script src="chrome://resources/js/cr/ui/list_item.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/grid.js"></script>
+<script src="grid_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/grid_test.js b/chrome/test/data/webui/grid_test.js
new file mode 100644
index 0000000..45b64d0
--- /dev/null
+++ b/chrome/test/data/webui/grid_test.js
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testGetColumnCount() {
+  var g = cr.ui.Grid.prototype;
+  g.measured_ = {
+    height: 8,
+    marginTop: 0,
+    marginBottom: 0,
+    width: 10,
+    marginLeft: 0,
+    marginRight: 0
+  };
+  var columns = g.getColumnCount_();
+  g.measured_.width = 0;
+  columns = g.getColumnCount_();
+  // Item width equals 0.
+  assertEquals(0, columns);
+
+  g.measured_.width = 10;
+  columns = g.getColumnCount_();
+  // No item in the list.
+  assertEquals(0, columns);
+
+  g.dataModel_ = new cr.ui.ArrayDataModel([0, 1, 2]);
+  g.horizontalPadding_ = 0;
+  g.clientWidthWithoutScrollbar_ = 8;
+  columns = g.getColumnCount_();
+  // Client width is smaller than item width.
+  assertEquals(0, columns);
+
+  g.clientWidthWithoutScrollbar_ = 20;
+  // Client height can fit two rows.
+  g.clientHeight_ = 16;
+  columns = g.getColumnCount_();
+  assertEquals(2, columns);
+
+  // Client height can not fit two rows. A scroll bar is needed.
+  g.clientHeight_ = 15;
+  g.clientWidthWithScrollbar_ = 18;
+  columns = g.getColumnCount_();
+  // Can not fit two columns due to the scroll bar.
+  assertEquals(1, columns);
+
+  g.clientHeight_ = 16;
+  g.measured_.marginTop = 1;
+  columns = g.getColumnCount_();
+  // Can fit two columns due to uncollapse margin.
+  assertEquals(2, columns);
+
+  g.measured_.marginBottom = 1;
+  columns = g.getColumnCount_();
+  // Can not fit two columns due to margin.
+  assertEquals(1, columns);
+
+  g.measured_.marginTop = 0;
+  g.measured_.marginBottom = 0;
+  g.measured_.marginLeft = 1;
+  columns = g.getColumnCount_();
+  // Can fit two columns due to uncollapse margin.
+  assertEquals(2, columns);
+
+  g.measured_.marginRight = 1;
+  columns = g.getColumnCount_();
+  // Can not fit two columns due to margin on left and right side.
+  assertEquals(1, columns);
+
+  g.measured_.marginRight = 0;
+  g.horizontalPadding_ = 2;
+  g.clientWidthWithoutScrollbar_ = 22;
+  columns = g.getColumnCount_();
+  // Can fit two columns as (22-2=)20px width is avaiable for grid items.
+  assertEquals(2, columns);
+
+  g.horizontalPadding_ = 3;
+  columns = g.getColumnCount_();
+  // Can not fit two columns due to bigger horizontal padding.
+  assertEquals(1, columns);
+}
diff --git a/chrome/test/data/webui/i18n_behavior_test.html b/chrome/test/data/webui/i18n_behavior_test.html
index 306f743..e69d10a 100644
--- a/chrome/test/data/webui/i18n_behavior_test.html
+++ b/chrome/test/data/webui/i18n_behavior_test.html
@@ -1,52 +1,9 @@
 <!doctype html>
 <html>
 <body>
-<script>
-
-var allowedByDefault = '<a href="https://google.com">Google!</a>';
-var text = 'I\'m just text, nobody should have a problem with me!';
-var nonBreakingSpace = 'A\u00a0B\u00a0C';  // \u00a0 is a unicode nbsp.
-
-function setUpPage() {
-  loadTimeData.data = {
-    'allowedByDefault': allowedByDefault,
-    'customAttr': '<a is="action-link">Take action!</a>',
-    'optionalTag': '<img>',
-    'javascriptHref': '<a href="javascript:alert(1)">teh hax</a>',
-    'script': '<script>alert(/xss/)</scr' + 'ipt>',
-    'text': text,
-    'nonBreakingSpace': nonBreakingSpace,
-  };
-}
-
-function testI18n() {
-  assertEquals(text, I18nBehavior.i18n('text'));
-  assertEquals(nonBreakingSpace, I18nBehavior.i18n('nonBreakingSpace'));
-
-  assertThrows(function() { I18nBehavior.i18n('customAttr'); });
-  assertThrows(function() { I18nBehavior.i18n('optionalTag'); });
-  assertThrows(function() { I18nBehavior.i18n('javascriptHref'); });
-  assertThrows(function() { I18nBehavior.i18n('script'); });
-}
-
-function testI18nAdvanced() {
-  assertEquals(
-      allowedByDefault,
-      I18nBehavior.i18nAdvanced('allowedByDefault'));
-  I18nBehavior.i18nAdvanced('customAttr', {attrs: ['is']});
-  I18nBehavior.i18nAdvanced('optionalTag', {tags: ['img']});
-}
-
-function testI18nDynamic() {
-  var locale = 'en';
-  assertEquals(text, I18nBehavior.i18nDynamic(locale, 'text'));
-}
-
-function testI18nExists() {
-  assertTrue(I18nBehavior.i18nExists('text'));
-  assertFalse(I18nBehavior.i18nExists('missingText'));
-}
-
-</script>
+<script src="chrome://resources/js/load_time_data.js"></script>
+<script src="chrome://resources/js/parse_html_subset.js"></script>
+<script src="chrome://resources/js/i18n_behavior.js"></script>
+<script src="i18n_behavior_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/i18n_behavior_test.js b/chrome/test/data/webui/i18n_behavior_test.js
new file mode 100644
index 0000000..f728fa606
--- /dev/null
+++ b/chrome/test/data/webui/i18n_behavior_test.js
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var allowedByDefault = '<a href="https://google.com">Google!</a>';
+var text = 'I\'m just text, nobody should have a problem with me!';
+var nonBreakingSpace = 'A\u00a0B\u00a0C';  // \u00a0 is a unicode nbsp.
+
+function setUpPage() {
+  loadTimeData.data = {
+    'allowedByDefault': allowedByDefault,
+    'customAttr': '<a is="action-link">Take action!</a>',
+    'optionalTag': '<img>',
+    'javascriptHref': '<a href="javascript:alert(1)">teh hax</a>',
+    'script': '<script>alert(/xss/)</scr' +
+        'ipt>',
+    'text': text,
+    'nonBreakingSpace': nonBreakingSpace,
+  };
+}
+
+function testI18n() {
+  assertEquals(text, I18nBehavior.i18n('text'));
+  assertEquals(nonBreakingSpace, I18nBehavior.i18n('nonBreakingSpace'));
+
+  assertThrows(function() {
+    I18nBehavior.i18n('customAttr');
+  });
+  assertThrows(function() {
+    I18nBehavior.i18n('optionalTag');
+  });
+  assertThrows(function() {
+    I18nBehavior.i18n('javascriptHref');
+  });
+  assertThrows(function() {
+    I18nBehavior.i18n('script');
+  });
+}
+
+function testI18nAdvanced() {
+  assertEquals(allowedByDefault, I18nBehavior.i18nAdvanced('allowedByDefault'));
+  I18nBehavior.i18nAdvanced('customAttr', {attrs: ['is']});
+  I18nBehavior.i18nAdvanced('optionalTag', {tags: ['img']});
+}
+
+function testI18nDynamic() {
+  var locale = 'en';
+  assertEquals(text, I18nBehavior.i18nDynamic(locale, 'text'));
+}
+
+function testI18nExists() {
+  assertTrue(I18nBehavior.i18nExists('text'));
+  assertFalse(I18nBehavior.i18nExists('missingText'));
+}
diff --git a/chrome/test/data/webui/i18n_process_css_test.html b/chrome/test/data/webui/i18n_process_css_test.html
index 85ba748..550e555 100644
--- a/chrome/test/data/webui/i18n_process_css_test.html
+++ b/chrome/test/data/webui/i18n_process_css_test.html
@@ -1,30 +1,9 @@
 <!doctype html>
-<style>
-<include src="../../../../ui/webui/resources/css/i18n_process.css">
-</style>
-<h1 i18n-content="buy"></h1>
-<span i18n-values=".innerHTML:link"></span>
-<script>
-
-function testI18nProcess_NbspPlaceholder() {
-  var h1 = document.querySelector('h1');
-  var span = document.querySelector('span');
-
-  assertFalse(document.documentElement.hasAttribute('i18n-processed'));
-  assertEquals('', h1.textContent);
-  assertEquals('', span.textContent);
-
-  /* We can't check that the non-breaking space hack actually works because it
-   * uses :psuedo-elements that are inaccessible to the DOM. Let's just check
-   * that they're not auto-collapsed. */
-  assertNotEqual(0, h1.offsetHeight);
-  assertNotEqual(0, span.offsetHeight);
-
-  h1.removeAttribute('i18n-content');
-  assertEquals(0, h1.offsetHeight);
-
-  span.removeAttribute('i18n-values');
-  assertEquals(0, span.offsetHeight);
-}
-
-</script>
+<head>
+  <link rel="stylesheet" href="chrome://resources/css/i18n_process.css">
+</head>
+<body>
+  <h1 i18n-content="buy"></h1>
+  <span i18n-values=".innerHTML:link"></span>
+  <script src="i18n_process_css_test.js"></script>
+</body>
diff --git a/chrome/test/data/webui/i18n_process_css_test.js b/chrome/test/data/webui/i18n_process_css_test.js
new file mode 100644
index 0000000..6b5d9899
--- /dev/null
+++ b/chrome/test/data/webui/i18n_process_css_test.js
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testI18nProcess_NbspPlaceholder() {
+  var h1 = document.querySelector('h1');
+  var span = document.querySelector('span');
+
+  assertFalse(document.documentElement.hasAttribute('i18n-processed'));
+  assertEquals('', h1.textContent);
+  assertEquals('', span.textContent);
+
+  /* We can't check that the non-breaking space hack actually works because it
+   * uses :psuedo-elements that are inaccessible to the DOM. Let's just check
+   * that they're not auto-collapsed. */
+  assertNotEqual(0, h1.offsetHeight);
+  assertNotEqual(0, span.offsetHeight);
+
+  h1.removeAttribute('i18n-content');
+  assertEquals(0, h1.offsetHeight);
+
+  span.removeAttribute('i18n-values');
+  assertEquals(0, span.offsetHeight);
+}
diff --git a/chrome/test/data/webui/icon_test.html b/chrome/test/data/webui/icon_test.html
index 8d28d6d4..f0fe4ae 100644
--- a/chrome/test/data/webui/icon_test.html
+++ b/chrome/test/data/webui/icon_test.html
@@ -1,51 +1,9 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-function testGetFaviconForPageURL() {
-  var url = 'http://foo.com';
-  var expectedDesktop = '-webkit-image-set(' +
-      'url("chrome://favicon2/?size=16&scale_factor=1x&page_url=' +
-      encodeURIComponent('http://foo.com') +
-      '&allow_google_server_fallback=0") 1x, ' +
-      'url("chrome://favicon2/?size=16&scale_factor=2x&page_url=' +
-      encodeURIComponent('http://foo.com') +
-      '&allow_google_server_fallback=0") 2x)';
-  var expectedOther = '-webkit-image-set(' +
-      'url("chrome://favicon2/?size=16&scale_factor=1x&page_url=' +
-      encodeURIComponent('http://foo.com') +
-      '&allow_google_server_fallback=0") ' +
-      window.devicePixelRatio + 'x)';
-
-  var isDesktop = cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux || cr.isLacros;
-  var expected = isDesktop ? expectedDesktop : expectedOther;
-  assertEquals(expected, cr.icon.getFaviconForPageURL(url));
-}
-
-function testGetFavicon() {
-  var url = 'http://foo.com/foo.ico';
-  var expectedDesktop = '-webkit-image-set(' +
-      'url("chrome://favicon2/?size=16&scale_factor=1x&icon_url=' +
-      encodeURIComponent('http://foo.com/foo.ico')+'") 1x, ' +
-      'url("chrome://favicon2/?size=16&scale_factor=2x&icon_url=' +
-      encodeURIComponent('http://foo.com/foo.ico')+'") 2x)';
-  var expectedOther = '-webkit-image-set(' +
-      'url("chrome://favicon2/?size=16&scale_factor=1x&icon_url=' +
-      encodeURIComponent('http://foo.com/foo.ico')+'") ' +
-      window.devicePixelRatio + 'x)';
-
-  var isDesktop = cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux || cr.isLacros;
-  var expected = isDesktop ? expectedDesktop : expectedOther;
-  assertEquals(expected, cr.icon.getFavicon(url));
-}
-
-function testGetFileIconUrl() {
-  assertEquals(cr.icon.getFileIconUrl('file path'),
-               'chrome://fileicon/?path=file+path&scale=' +
-                   window.devicePixelRatio + 'x');
-}
-
-</script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="chrome://resources/js/icon.js"></script>
+<script src="icon_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/icon_test.js b/chrome/test/data/webui/icon_test.js
new file mode 100644
index 0000000..4281410
--- /dev/null
+++ b/chrome/test/data/webui/icon_test.js
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testGetFaviconForPageURL() {
+  var url = 'http://foo.com';
+  var expectedDesktop = '-webkit-image-set(' +
+      'url("chrome://favicon2/?size=16&scale_factor=1x&page_url=' +
+      encodeURIComponent('http://foo.com') +
+      '&allow_google_server_fallback=0") 1x, ' +
+      'url("chrome://favicon2/?size=16&scale_factor=2x&page_url=' +
+      encodeURIComponent('http://foo.com') +
+      '&allow_google_server_fallback=0") 2x)';
+  var expectedOther = '-webkit-image-set(' +
+      'url("chrome://favicon2/?size=16&scale_factor=1x&page_url=' +
+      encodeURIComponent('http://foo.com') +
+      '&allow_google_server_fallback=0") ' + window.devicePixelRatio + 'x)';
+
+  var isDesktop =
+      cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux || cr.isLacros;
+  var expected = isDesktop ? expectedDesktop : expectedOther;
+  assertEquals(expected, cr.icon.getFaviconForPageURL(url));
+}
+
+function testGetFavicon() {
+  var url = 'http://foo.com/foo.ico';
+  var expectedDesktop = '-webkit-image-set(' +
+      'url("chrome://favicon2/?size=16&scale_factor=1x&icon_url=' +
+      encodeURIComponent('http://foo.com/foo.ico') + '") 1x, ' +
+      'url("chrome://favicon2/?size=16&scale_factor=2x&icon_url=' +
+      encodeURIComponent('http://foo.com/foo.ico') + '") 2x)';
+  var expectedOther = '-webkit-image-set(' +
+      'url("chrome://favicon2/?size=16&scale_factor=1x&icon_url=' +
+      encodeURIComponent('http://foo.com/foo.ico') + '") ' +
+      window.devicePixelRatio + 'x)';
+
+  var isDesktop =
+      cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux || cr.isLacros;
+  var expected = isDesktop ? expectedDesktop : expectedOther;
+  assertEquals(expected, cr.icon.getFavicon(url));
+}
+
+function testGetFileIconUrl() {
+  assertEquals(
+      cr.icon.getFileIconUrl('file path'),
+      'chrome://fileicon/?path=file+path&scale=' + window.devicePixelRatio +
+          'x');
+}
diff --git a/chrome/test/data/webui/list_selection_model_test.html b/chrome/test/data/webui/list_selection_model_test.html
index 153db73..db04ccf 100644
--- a/chrome/test/data/webui/list_selection_model_test.html
+++ b/chrome/test/data/webui/list_selection_model_test.html
@@ -1,288 +1,10 @@
 <!DOCTYPE html>
 <html>
-<head>
-<script src="list_selection_model_test_util.js"></script>
-</head>
 <body>
-
-<script>
-function createSelectionModel(len, opt_dependentLeadItem) {
-  var sm = new cr.ui.ListSelectionModel(len);
-  sm.independentLeadItem_ = !opt_dependentLeadItem;
-  return sm;
-}
-
-function testAdjust1() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
-  adjust(sm, 0, 10, 0);
-
-  assertEquals(90, sm.leadIndex);
-  assertEquals(90, sm.anchorIndex);
-  assertEquals(90, sm.selectedIndex);
-}
-
-function testAdjust2() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 50;
-  adjust(sm, 60, 10, 0);
-
-  assertEquals(50, sm.leadIndex);
-  assertEquals(50, sm.anchorIndex);
-  assertEquals(50, sm.selectedIndex);
-}
-
-function testAdjust3() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
-  adjust(sm, 0, 0, 10);
-
-  assertEquals(110, sm.leadIndex);
-  assertEquals(110, sm.anchorIndex);
-  assertEquals(110, sm.selectedIndex);
-}
-
-function testAdjust4() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = 100;
-  sm.selectRange(100, 110);
-
-  adjust(sm, 0, 10, 5);
-
-  assertEquals(95, sm.leadIndex);
-  assertEquals(95, sm.anchorIndex);
-  assertArrayEquals(range(95, 105), sm.selectedIndexes);
-}
-
-function testAdjust5() {
-  var sm = createSelectionModel(100);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 99;
-
-  adjust(sm, 99, 1, 0);
-
-  assertEquals(98, sm.leadIndex, 'lead');
-  assertEquals(98, sm.anchorIndex, 'anchor');
-  assertArrayEquals([98], sm.selectedIndexes);
-}
-
-function testAdjust6() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = 105;
-  sm.selectRange(100, 110);
-
-  // Remove 100 - 105
-  adjust(sm, 100, 5, 0);
-
-  assertEquals(100, sm.leadIndex, 'lead');
-  assertEquals(100, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(100, 105), sm.selectedIndexes);
-}
-
-function testAdjust7() {
-  var sm = createSelectionModel(1);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 0;
-
-  adjust(sm, 0, 0, 10);
-
-  assertEquals(10, sm.leadIndex, 'lead');
-  assertEquals(10, sm.anchorIndex, 'anchor');
-  assertArrayEquals([10], sm.selectedIndexes);
-}
-
-function testAdjust8() {
-  var sm = createSelectionModel(100);
-
-  sm.leadIndex = sm.anchorIndex = 50;
-  sm.selectAll();
-
-  adjust(sm, 10, 80, 0);
-
-  assertEquals(-1, sm.leadIndex, 'lead');
-  assertEquals(-1, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(0, 19), sm.selectedIndexes);
-}
-
-function testAdjust9() {
-  var sm = createSelectionModel(10);
-
-  sm.leadIndex = sm.anchorIndex = 5;
-  sm.selectAll();
-
-  // Remove all
-  adjust(sm, 0, 10, 0);
-
-  assertEquals(-1, sm.leadIndex, 'lead');
-  assertEquals(-1, sm.anchorIndex, 'anchor');
-  assertArrayEquals([], sm.selectedIndexes);
-}
-
-function testAdjust10() {
-  var sm = createSelectionModel(10);
-
-  sm.leadIndex = sm.anchorIndex = 5;
-  sm.selectAll();
-
-  adjust(sm, 0, 10, 20);
-
-  assertEquals(5, sm.leadIndex, 'lead');
-  assertEquals(5, sm.anchorIndex, 'anchor');
-  assertArrayEquals([5], sm.selectedIndexes);
-}
-
-function testAdjust11() {
-  var sm = createSelectionModel(20);
-
-  sm.leadIndex = sm.anchorIndex = 10;
-  sm.selectAll();
-
-  adjust(sm, 5, 20, 10);
-
-  assertEquals(-1, sm.leadIndex, 'lead');
-  assertEquals(-1, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(0, 4), sm.selectedIndexes);
-}
-
-function testAdjust12() {
-  var sm = createSelectionModel(20, true);
-
-  sm.selectAll();
-  sm.leadIndex = sm.anchorIndex = 10;
-
-  adjust(sm, 5, 20, 10);
-
-  assertEquals(0, sm.leadIndex, 'lead');
-  assertEquals(0, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(0, 4), sm.selectedIndexes);
-}
-
-function testAdjust13() {
-  var sm = createSelectionModel(20, true);
-
-  sm.selectAll();
-  sm.leadIndex = sm.anchorIndex = 15;
-
-  adjust(sm, 5, 5, 0);
-
-  assertEquals(10, sm.leadIndex, 'lead');
-  assertEquals(10, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(0, 14), sm.selectedIndexes);
-}
-
-function testAdjust14() {
-  var sm = createSelectionModel(5, true);
-
-  sm.selectedIndexes = [2, 3];
-  sm.leadIndex = sm.anchorIndex = 3;
-
-  adjust(sm, 2, 2, 0);
-
-  assertEquals(2, sm.leadIndex, 'lead');
-  assertEquals(2, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(2, 2), sm.selectedIndexes);
-}
-
-function testAdjust15() {
-  var sm = createSelectionModel(7, true);
-
-  sm.selectedIndexes = [1, 3, 5];
-  sm.leadIndex = sm.anchorIndex = 1;
-
-  adjust(sm, 1, 1, 0);
-  adjust(sm, 2, 1, 0);
-  adjust(sm, 3, 1, 0);
-
-  assertEquals(3, sm.leadIndex, 'lead');
-  assertEquals(3, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(3, 3), sm.selectedIndexes);
-}
-
-function testAdjust16() {
-  var sm = createSelectionModel(7, true);
-
-  sm.selectedIndexes = [1, 3, 5];
-  sm.leadIndex = sm.anchorIndex = 3;
-
-  adjust(sm, 1, 1, 0);
-  adjust(sm, 2, 1, 0);
-  adjust(sm, 3, 1, 0);
-
-  assertEquals(3, sm.leadIndex, 'lead');
-  assertEquals(3, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(3, 3), sm.selectedIndexes);
-}
-
-function testAdjust17() {
-  var sm = createSelectionModel(7, true);
-
-  sm.selectedIndexes = [1, 3, 5];
-  sm.leadIndex = sm.anchorIndex = 5;
-
-  adjust(sm, 1, 1, 0);
-  adjust(sm, 2, 1, 0);
-  adjust(sm, 3, 1, 0);
-
-  assertEquals(3, sm.leadIndex, 'lead');
-  assertEquals(3, sm.anchorIndex, 'anchor');
-  assertArrayEquals(range(3, 3), sm.selectedIndexes);
-}
-
-function testLeadAndAnchor1() {
-  var sm = createSelectionModel(20, true);
-
-  sm.selectAll();
-  sm.leadIndex = sm.anchorIndex = 10;
-
-  assertEquals(10, sm.leadIndex, 'lead');
-  assertEquals(10, sm.anchorIndex, 'anchor');
-}
-
-function testLeadAndAnchor2() {
-  var sm = createSelectionModel(20, true);
-
-  sm.leadIndex = sm.anchorIndex = 10;
-  sm.selectAll();
-
-  assertEquals(0, sm.leadIndex, 'lead');
-  assertEquals(0, sm.anchorIndex, 'anchor');
-}
-
-function testSelectAll() {
-  var sm = createSelectionModel(10);
-
-  var changes = null;
-  sm.addEventListener('change', function(e) {
-    changes = e.changes;
-  });
-
-  sm.selectAll();
-
-  assertArrayEquals(range(0, 9), sm.selectedIndexes);
-  assertArrayEquals(range(0, 9),
-                    changes.map(function(change) { return change.index; }));
-}
-
-function testSelectAllOnEmptyList() {
-  var sm = createSelectionModel(0);
-
-  var changes = null;
-  sm.addEventListener('change', function(e) {
-    changes = e.changes;
-  });
-
-  sm.selectAll();
-
-  assertArrayEquals([], sm.selectedIndexes);
-  assertEquals(null, changes);
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+<script src="list_selection_model_test_util.js"></script>
+<script src="list_selection_model_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/list_selection_model_test.js b/chrome/test/data/webui/list_selection_model_test.js
new file mode 100644
index 0000000..a765e36f
--- /dev/null
+++ b/chrome/test/data/webui/list_selection_model_test.js
@@ -0,0 +1,280 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function createSelectionModel(len, opt_dependentLeadItem) {
+  var sm = new cr.ui.ListSelectionModel(len);
+  sm.independentLeadItem_ = !opt_dependentLeadItem;
+  return sm;
+}
+
+function testAdjust1() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
+  adjust(sm, 0, 10, 0);
+
+  assertEquals(90, sm.leadIndex);
+  assertEquals(90, sm.anchorIndex);
+  assertEquals(90, sm.selectedIndex);
+}
+
+function testAdjust2() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 50;
+  adjust(sm, 60, 10, 0);
+
+  assertEquals(50, sm.leadIndex);
+  assertEquals(50, sm.anchorIndex);
+  assertEquals(50, sm.selectedIndex);
+}
+
+function testAdjust3() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
+  adjust(sm, 0, 0, 10);
+
+  assertEquals(110, sm.leadIndex);
+  assertEquals(110, sm.anchorIndex);
+  assertEquals(110, sm.selectedIndex);
+}
+
+function testAdjust4() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = 100;
+  sm.selectRange(100, 110);
+
+  adjust(sm, 0, 10, 5);
+
+  assertEquals(95, sm.leadIndex);
+  assertEquals(95, sm.anchorIndex);
+  assertArrayEquals(range(95, 105), sm.selectedIndexes);
+}
+
+function testAdjust5() {
+  var sm = createSelectionModel(100);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 99;
+
+  adjust(sm, 99, 1, 0);
+
+  assertEquals(98, sm.leadIndex, 'lead');
+  assertEquals(98, sm.anchorIndex, 'anchor');
+  assertArrayEquals([98], sm.selectedIndexes);
+}
+
+function testAdjust6() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = 105;
+  sm.selectRange(100, 110);
+
+  // Remove 100 - 105
+  adjust(sm, 100, 5, 0);
+
+  assertEquals(100, sm.leadIndex, 'lead');
+  assertEquals(100, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(100, 105), sm.selectedIndexes);
+}
+
+function testAdjust7() {
+  var sm = createSelectionModel(1);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 0;
+
+  adjust(sm, 0, 0, 10);
+
+  assertEquals(10, sm.leadIndex, 'lead');
+  assertEquals(10, sm.anchorIndex, 'anchor');
+  assertArrayEquals([10], sm.selectedIndexes);
+}
+
+function testAdjust8() {
+  var sm = createSelectionModel(100);
+
+  sm.leadIndex = sm.anchorIndex = 50;
+  sm.selectAll();
+
+  adjust(sm, 10, 80, 0);
+
+  assertEquals(-1, sm.leadIndex, 'lead');
+  assertEquals(-1, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(0, 19), sm.selectedIndexes);
+}
+
+function testAdjust9() {
+  var sm = createSelectionModel(10);
+
+  sm.leadIndex = sm.anchorIndex = 5;
+  sm.selectAll();
+
+  // Remove all
+  adjust(sm, 0, 10, 0);
+
+  assertEquals(-1, sm.leadIndex, 'lead');
+  assertEquals(-1, sm.anchorIndex, 'anchor');
+  assertArrayEquals([], sm.selectedIndexes);
+}
+
+function testAdjust10() {
+  var sm = createSelectionModel(10);
+
+  sm.leadIndex = sm.anchorIndex = 5;
+  sm.selectAll();
+
+  adjust(sm, 0, 10, 20);
+
+  assertEquals(5, sm.leadIndex, 'lead');
+  assertEquals(5, sm.anchorIndex, 'anchor');
+  assertArrayEquals([5], sm.selectedIndexes);
+}
+
+function testAdjust11() {
+  var sm = createSelectionModel(20);
+
+  sm.leadIndex = sm.anchorIndex = 10;
+  sm.selectAll();
+
+  adjust(sm, 5, 20, 10);
+
+  assertEquals(-1, sm.leadIndex, 'lead');
+  assertEquals(-1, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(0, 4), sm.selectedIndexes);
+}
+
+function testAdjust12() {
+  var sm = createSelectionModel(20, true);
+
+  sm.selectAll();
+  sm.leadIndex = sm.anchorIndex = 10;
+
+  adjust(sm, 5, 20, 10);
+
+  assertEquals(0, sm.leadIndex, 'lead');
+  assertEquals(0, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(0, 4), sm.selectedIndexes);
+}
+
+function testAdjust13() {
+  var sm = createSelectionModel(20, true);
+
+  sm.selectAll();
+  sm.leadIndex = sm.anchorIndex = 15;
+
+  adjust(sm, 5, 5, 0);
+
+  assertEquals(10, sm.leadIndex, 'lead');
+  assertEquals(10, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(0, 14), sm.selectedIndexes);
+}
+
+function testAdjust14() {
+  var sm = createSelectionModel(5, true);
+
+  sm.selectedIndexes = [2, 3];
+  sm.leadIndex = sm.anchorIndex = 3;
+
+  adjust(sm, 2, 2, 0);
+
+  assertEquals(2, sm.leadIndex, 'lead');
+  assertEquals(2, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(2, 2), sm.selectedIndexes);
+}
+
+function testAdjust15() {
+  var sm = createSelectionModel(7, true);
+
+  sm.selectedIndexes = [1, 3, 5];
+  sm.leadIndex = sm.anchorIndex = 1;
+
+  adjust(sm, 1, 1, 0);
+  adjust(sm, 2, 1, 0);
+  adjust(sm, 3, 1, 0);
+
+  assertEquals(3, sm.leadIndex, 'lead');
+  assertEquals(3, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(3, 3), sm.selectedIndexes);
+}
+
+function testAdjust16() {
+  var sm = createSelectionModel(7, true);
+
+  sm.selectedIndexes = [1, 3, 5];
+  sm.leadIndex = sm.anchorIndex = 3;
+
+  adjust(sm, 1, 1, 0);
+  adjust(sm, 2, 1, 0);
+  adjust(sm, 3, 1, 0);
+
+  assertEquals(3, sm.leadIndex, 'lead');
+  assertEquals(3, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(3, 3), sm.selectedIndexes);
+}
+
+function testAdjust17() {
+  var sm = createSelectionModel(7, true);
+
+  sm.selectedIndexes = [1, 3, 5];
+  sm.leadIndex = sm.anchorIndex = 5;
+
+  adjust(sm, 1, 1, 0);
+  adjust(sm, 2, 1, 0);
+  adjust(sm, 3, 1, 0);
+
+  assertEquals(3, sm.leadIndex, 'lead');
+  assertEquals(3, sm.anchorIndex, 'anchor');
+  assertArrayEquals(range(3, 3), sm.selectedIndexes);
+}
+
+function testLeadAndAnchor1() {
+  var sm = createSelectionModel(20, true);
+
+  sm.selectAll();
+  sm.leadIndex = sm.anchorIndex = 10;
+
+  assertEquals(10, sm.leadIndex, 'lead');
+  assertEquals(10, sm.anchorIndex, 'anchor');
+}
+
+function testLeadAndAnchor2() {
+  var sm = createSelectionModel(20, true);
+
+  sm.leadIndex = sm.anchorIndex = 10;
+  sm.selectAll();
+
+  assertEquals(0, sm.leadIndex, 'lead');
+  assertEquals(0, sm.anchorIndex, 'anchor');
+}
+
+function testSelectAll() {
+  var sm = createSelectionModel(10);
+
+  var changes = null;
+  sm.addEventListener('change', function(e) {
+    changes = e.changes;
+  });
+
+  sm.selectAll();
+
+  assertArrayEquals(range(0, 9), sm.selectedIndexes);
+  assertArrayEquals(range(0, 9), changes.map(function(change) {
+    return change.index;
+  }));
+}
+
+function testSelectAllOnEmptyList() {
+  var sm = createSelectionModel(0);
+
+  var changes = null;
+  sm.addEventListener('change', function(e) {
+    changes = e.changes;
+  });
+
+  sm.selectAll();
+
+  assertArrayEquals([], sm.selectedIndexes);
+  assertEquals(null, changes);
+}
diff --git a/chrome/test/data/webui/list_single_selection_model_test.html b/chrome/test/data/webui/list_single_selection_model_test.html
index af006d5..0190b77 100644
--- a/chrome/test/data/webui/list_single_selection_model_test.html
+++ b/chrome/test/data/webui/list_single_selection_model_test.html
@@ -1,106 +1,10 @@
 <!DOCTYPE html>
 <html>
-<head>
-<script src="list_selection_model_test_util.js"></script>
-</head>
 <body>
-
-<script>
-
-function createSelectionModel(len, opt_dependentLeadItem) {
-  var sm = new cr.ui.ListSingleSelectionModel(len);
-  sm.independentLeadItem_ = !opt_dependentLeadItem;
-  return sm;
-}
-
-function testAdjust1() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
-  adjust(sm, 0, 10, 0);
-
-  assertEquals(90, sm.leadIndex);
-  assertEquals(90, sm.anchorIndex);
-  assertEquals(90, sm.selectedIndex);
-}
-
-function testAdjust2() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 50;
-  adjust(sm, 60, 10, 0);
-
-  assertEquals(50, sm.leadIndex);
-  assertEquals(50, sm.anchorIndex);
-  assertEquals(50, sm.selectedIndex);
-}
-
-function testAdjust3() {
-  var sm = createSelectionModel(200);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
-  adjust(sm, 0, 0, 10);
-
-  assertEquals(110, sm.leadIndex);
-  assertEquals(110, sm.anchorIndex);
-  assertEquals(110, sm.selectedIndex);
-}
-
-function testAdjust4() {
-  var sm = createSelectionModel(100);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 99;
-
-  adjust(sm, 99, 1, 0);
-
-  assertEquals(-1, sm.leadIndex, 'lead');
-  assertEquals(-1, sm.anchorIndex, 'anchor');
-  assertArrayEquals([], sm.selectedIndexes);
-}
-
-function testAdjust5() {
-  var sm = createSelectionModel(1);
-
-  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 0;
-
-  adjust(sm, 0, 0, 10);
-
-  assertEquals(10, sm.leadIndex,'lead');
-  assertEquals(10, sm.anchorIndex, 'anchor');
-  assertArrayEquals([10], sm.selectedIndexes);
-}
-
-function testSelectedIndex1() {
-  var sm = createSelectionModel(100, true);
-
-  sm.selectedIndex = 99;
-
-  assertEquals(99, sm.leadIndex, 'lead');
-  assertEquals(99, sm.anchorIndex, 'anchor');
-  assertArrayEquals([99], sm.selectedIndexes);
-}
-
-function testLeadIndex1() {
-  var sm = createSelectionModel(100);
-
-  sm.leadIndex = 99;
-
-  assertEquals(99, sm.leadIndex, 'lead');
-  assertEquals(99, sm.anchorIndex, 'anchor');
-  assertArrayEquals([], sm.selectedIndexes);
-}
-
-function testLeadIndex2() {
-  var sm = createSelectionModel(100, true);
-
-  sm.leadIndex = 99;
-
-  assertEquals(-1, sm.leadIndex, 'lead');
-  assertEquals(-1, sm.anchorIndex, 'anchor');
-  assertArrayEquals([], sm.selectedIndexes);
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script>
+<script src="list_selection_model_test_util.js"></script>
+<script src="list_single_selection_model_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/list_single_selection_model_test.js b/chrome/test/data/webui/list_single_selection_model_test.js
new file mode 100644
index 0000000..3e3c5335
--- /dev/null
+++ b/chrome/test/data/webui/list_single_selection_model_test.js
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function createSelectionModel(len, opt_dependentLeadItem) {
+  var sm = new cr.ui.ListSingleSelectionModel(len);
+  sm.independentLeadItem_ = !opt_dependentLeadItem;
+  return sm;
+}
+
+function testAdjust1() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
+  adjust(sm, 0, 10, 0);
+
+  assertEquals(90, sm.leadIndex);
+  assertEquals(90, sm.anchorIndex);
+  assertEquals(90, sm.selectedIndex);
+}
+
+function testAdjust2() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 50;
+  adjust(sm, 60, 10, 0);
+
+  assertEquals(50, sm.leadIndex);
+  assertEquals(50, sm.anchorIndex);
+  assertEquals(50, sm.selectedIndex);
+}
+
+function testAdjust3() {
+  var sm = createSelectionModel(200);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 100;
+  adjust(sm, 0, 0, 10);
+
+  assertEquals(110, sm.leadIndex);
+  assertEquals(110, sm.anchorIndex);
+  assertEquals(110, sm.selectedIndex);
+}
+
+function testAdjust4() {
+  var sm = createSelectionModel(100);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 99;
+
+  adjust(sm, 99, 1, 0);
+
+  assertEquals(-1, sm.leadIndex, 'lead');
+  assertEquals(-1, sm.anchorIndex, 'anchor');
+  assertArrayEquals([], sm.selectedIndexes);
+}
+
+function testAdjust5() {
+  var sm = createSelectionModel(1);
+
+  sm.leadIndex = sm.anchorIndex = sm.selectedIndex = 0;
+
+  adjust(sm, 0, 0, 10);
+
+  assertEquals(10, sm.leadIndex, 'lead');
+  assertEquals(10, sm.anchorIndex, 'anchor');
+  assertArrayEquals([10], sm.selectedIndexes);
+}
+
+function testSelectedIndex1() {
+  var sm = createSelectionModel(100, true);
+
+  sm.selectedIndex = 99;
+
+  assertEquals(99, sm.leadIndex, 'lead');
+  assertEquals(99, sm.anchorIndex, 'anchor');
+  assertArrayEquals([99], sm.selectedIndexes);
+}
+
+function testLeadIndex1() {
+  var sm = createSelectionModel(100);
+
+  sm.leadIndex = 99;
+
+  assertEquals(99, sm.leadIndex, 'lead');
+  assertEquals(99, sm.anchorIndex, 'anchor');
+  assertArrayEquals([], sm.selectedIndexes);
+}
+
+function testLeadIndex2() {
+  var sm = createSelectionModel(100, true);
+
+  sm.leadIndex = 99;
+
+  assertEquals(-1, sm.leadIndex, 'lead');
+  assertEquals(-1, sm.anchorIndex, 'anchor');
+  assertArrayEquals([], sm.selectedIndexes);
+}
diff --git a/chrome/test/data/webui/list_test.html b/chrome/test/data/webui/list_test.html
index 4017d01..e0a8858 100644
--- a/chrome/test/data/webui/list_test.html
+++ b/chrome/test/data/webui/list_test.html
@@ -1,67 +1,14 @@
 <!DOCTYPE html>
 <html>
 <body>
-
-<script>
-
-function testClearPinnedItem() {
-  var list = document.createElement('ul');
-  list.style.position = 'absolute';
-  list.style.width = '800px';
-  list.style.height = '800px';
-  cr.ui.List.decorate(list);
-  document.body.appendChild(list);
-
-  var model = new cr.ui.ArrayDataModel(['Item A', 'Item B']);
-  list.dataModel = model;
-  list.selectionModel.setIndexSelected(0, true);
-  list.selectionModel.leadIndex = 0;
-  list.ensureLeadItemExists();
-
-  list.style.height = '0px';
-  model.splice(0, 1);
-
-  list.style.height = '800px';
-  list.redraw();
-  assertEquals('Item B',
-               list.querySelectorAll('li')[0].textContent);
-}
-
-function testClickOutsideListItem() {
-  const list = document.createElement('ul');
-  list.style.position = 'absolute';
-  list.style.width = '800px';
-  list.style.height = '800px';
-  cr.ui.List.decorate(list);
-  document.body.appendChild(list);
-
-  // Add a header inside the list.
-  const header = document.createElement('h1');
-  header.innerText = 'Title inside the list';
-  list.appendChild(header);
-
-  const model = new cr.ui.ArrayDataModel(['Item A', 'Item B']);
-  list.dataModel = model;
-
-  list.redraw();
-
-  const item = list.querySelector('li');
-  const span = document.createElement('span');
-  span.innerText = 'some text';
-  item.appendChild(span);
-
-  // Non-LI children should return null.
-  assertEquals(null, list.getListItemAncestor(header));
-
-  // It should return null for the list itself.
-  assertEquals(null, list.getListItemAncestor(list));
-
-  // Anything inside a LI should return the LI itself.
-  assertEquals(item, list.getListItemAncestor(item));
-  assertEquals(item, list.getListItemAncestor(span));
-}
-
-</script>
-
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/event_target.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list_item.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script>
+<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script>
+<script src="chrome://resources/js/cr/ui/list.js"></script>
+<script src="list_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/list_test.js b/chrome/test/data/webui/list_test.js
new file mode 100644
index 0000000..7f0dec9
--- /dev/null
+++ b/chrome/test/data/webui/list_test.js
@@ -0,0 +1,59 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testClearPinnedItem() {
+  var list = document.createElement('ul');
+  list.style.position = 'absolute';
+  list.style.width = '800px';
+  list.style.height = '800px';
+  cr.ui.List.decorate(list);
+  document.body.appendChild(list);
+
+  var model = new cr.ui.ArrayDataModel(['Item A', 'Item B']);
+  list.dataModel = model;
+  list.selectionModel.setIndexSelected(0, true);
+  list.selectionModel.leadIndex = 0;
+  list.ensureLeadItemExists();
+
+  list.style.height = '0px';
+  model.splice(0, 1);
+
+  list.style.height = '800px';
+  list.redraw();
+  assertEquals('Item B', list.querySelectorAll('li')[0].textContent);
+}
+
+function testClickOutsideListItem() {
+  const list = document.createElement('ul');
+  list.style.position = 'absolute';
+  list.style.width = '800px';
+  list.style.height = '800px';
+  cr.ui.List.decorate(list);
+  document.body.appendChild(list);
+
+  // Add a header inside the list.
+  const header = document.createElement('h1');
+  header.innerText = 'Title inside the list';
+  list.appendChild(header);
+
+  const model = new cr.ui.ArrayDataModel(['Item A', 'Item B']);
+  list.dataModel = model;
+
+  list.redraw();
+
+  const item = list.querySelector('li');
+  const span = document.createElement('span');
+  span.innerText = 'some text';
+  item.appendChild(span);
+
+  // Non-LI children should return null.
+  assertEquals(null, list.getListItemAncestor(header));
+
+  // It should return null for the list itself.
+  assertEquals(null, list.getListItemAncestor(list));
+
+  // Anything inside a LI should return the LI itself.
+  assertEquals(item, list.getListItemAncestor(item));
+  assertEquals(item, list.getListItemAncestor(span));
+}
diff --git a/chrome/test/data/webui/menu_button_test.html b/chrome/test/data/webui/menu_button_test.html
index 8009e76b..8ee6e854 100644
--- a/chrome/test/data/webui/menu_button_test.html
+++ b/chrome/test/data/webui/menu_button_test.html
@@ -1,104 +1,14 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-function testMenuShowAndHideEvents() {
-  var menu = document.createElement('div');
-  cr.ui.decorate(menu, cr.ui.Menu);
-  document.body.appendChild(menu);
-
-  var menuButton = document.createElement('div');
-  cr.ui.decorate(menuButton, cr.ui.MenuButton);
-  menuButton.menu = menu;
-  document.body.appendChild(menuButton);
-
-  var events = [];
-  menuButton.addEventListener('menushow', function(e) { events.push(e); });
-  menuButton.addEventListener('menuhide', function(e) { events.push(e); });
-
-  // Click to show menu.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertEquals(1, events.length);
-  assertEquals('menushow', events[0].type);
-  assertEquals(true, events[0].bubbles);
-  assertEquals(true, events[0].cancelable);
-  assertEquals(window, events[0].view);
-
-  // Click to hide menu by clicking the button.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertEquals(2, events.length);
-  assertEquals('menuhide', events[1].type);
-  assertEquals(true, events[1].bubbles);
-  assertEquals(false, events[1].cancelable);
-  assertEquals(window, events[1].view);
-  // The button must not appear highlighted.
-  assertTrue(menuButton.classList.contains('using-mouse'));
-
-  // Click to show menu and hide by clicking the outside of the button.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertEquals(3, events.length);
-  assertEquals('menushow', events[2].type);
-  document.dispatchEvent(new MouseEvent('mousedown'));
-  assertEquals(4, events.length);
-  assertEquals('menuhide', events[3].type);
-  // Emulate losing focus after clicking outside of the button.
-  menuButton.dispatchEvent(new Event('blur'));
-  // Focus highlight should not be suppressed anymore.
-  assertFalse(menuButton.classList.contains('using-mouse'));
-}
-
-function testFocusMoves() {
-  var menu = document.createElement('div');
-  var otherButton = document.createElement('button');
-  cr.ui.decorate(menu, cr.ui.Menu);
-  menu.addMenuItem({});
-  document.body.appendChild(menu);
-  document.body.appendChild(otherButton);
-
-  var menuButton = document.createElement('div');
-  cr.ui.decorate(menuButton, cr.ui.MenuButton);
-  // Allow to put focus on the menu button by focus().
-  menuButton.tabIndex = 1;
-  menuButton.menu = menu;
-  document.body.appendChild(menuButton);
-
-  // Case 1: Close by mouse click outside the menu.
-  otherButton.focus();
-  // Click to show menu.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertTrue(menuButton.isMenuShown());
-  // Click again to hide menu by clicking the button.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertFalse(menuButton.isMenuShown());
-  // Focus should be kept on the original place.
-  assertEquals(otherButton, document.activeElement);
-
-  // Case 2: Activate menu item with mouse.
-  menuButton.dispatchEvent(new MouseEvent('mousedown'));
-  assertTrue(menuButton.isMenuShown());
-  // Emulate choosing a menu item by mouse click.
-  var menuItem = menu.menuItems[0];
-  menuItem.selected = true;
-  menuItem.dispatchEvent(new MouseEvent('mouseup', {buttons: 1}));
-  assertFalse(menuButton.isMenuShown());
-  // Focus should be kept on the original place.
-  assertEquals(otherButton, document.activeElement);
-
-  // Case 3: Open menu and activate by keyboard.
-  menuButton.focus();
-  assertEquals(menuButton, document.activeElement);
-  // Open menu
-  menuButton.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
-  assertTrue(menuButton.isMenuShown(), 'menu opened');
-  // Select an item and activate
-  menu.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
-  menu.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
-  assertFalse(menuButton.isMenuShown(), 'menu closed');
-  // Focus should be still on the menu button.
-  assertEquals(menuButton, document.activeElement);
-}
-
-</script>
+<script src="chrome://resources/js/assert.js"></script>
+<script src="chrome://resources/js/event_tracker.js"></script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/position_util.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_button.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_item.js"></script>
+<script src="chrome://resources/js/cr/ui/menu.js"></script>
+<script src="menu_button_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/menu_button_test.js b/chrome/test/data/webui/menu_button_test.js
new file mode 100644
index 0000000..57f938e4
--- /dev/null
+++ b/chrome/test/data/webui/menu_button_test.js
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testMenuShowAndHideEvents() {
+  var menu = document.createElement('div');
+  cr.ui.decorate(menu, cr.ui.Menu);
+  document.body.appendChild(menu);
+
+  var menuButton = document.createElement('div');
+  cr.ui.decorate(menuButton, cr.ui.MenuButton);
+  menuButton.menu = menu;
+  document.body.appendChild(menuButton);
+
+  var events = [];
+  menuButton.addEventListener('menushow', function(e) {
+    events.push(e);
+  });
+  menuButton.addEventListener('menuhide', function(e) {
+    events.push(e);
+  });
+
+  // Click to show menu.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertEquals(1, events.length);
+  assertEquals('menushow', events[0].type);
+  assertEquals(true, events[0].bubbles);
+  assertEquals(true, events[0].cancelable);
+  assertEquals(window, events[0].view);
+
+  // Click to hide menu by clicking the button.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertEquals(2, events.length);
+  assertEquals('menuhide', events[1].type);
+  assertEquals(true, events[1].bubbles);
+  assertEquals(false, events[1].cancelable);
+  assertEquals(window, events[1].view);
+  // The button must not appear highlighted.
+  assertTrue(menuButton.classList.contains('using-mouse'));
+
+  // Click to show menu and hide by clicking the outside of the button.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertEquals(3, events.length);
+  assertEquals('menushow', events[2].type);
+  document.dispatchEvent(new MouseEvent('mousedown'));
+  assertEquals(4, events.length);
+  assertEquals('menuhide', events[3].type);
+  // Emulate losing focus after clicking outside of the button.
+  menuButton.dispatchEvent(new Event('blur'));
+  // Focus highlight should not be suppressed anymore.
+  assertFalse(menuButton.classList.contains('using-mouse'));
+}
+
+function testFocusMoves() {
+  var menu = document.createElement('div');
+  var otherButton = document.createElement('button');
+  cr.ui.decorate(menu, cr.ui.Menu);
+  menu.addMenuItem({});
+  document.body.appendChild(menu);
+  document.body.appendChild(otherButton);
+
+  var menuButton = document.createElement('div');
+  cr.ui.decorate(menuButton, cr.ui.MenuButton);
+  // Allow to put focus on the menu button by focus().
+  menuButton.tabIndex = 1;
+  menuButton.menu = menu;
+  document.body.appendChild(menuButton);
+
+  // Case 1: Close by mouse click outside the menu.
+  otherButton.focus();
+  // Click to show menu.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertTrue(menuButton.isMenuShown());
+  // Click again to hide menu by clicking the button.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertFalse(menuButton.isMenuShown());
+  // Focus should be kept on the original place.
+  assertEquals(otherButton, document.activeElement);
+
+  // Case 2: Activate menu item with mouse.
+  menuButton.dispatchEvent(new MouseEvent('mousedown'));
+  assertTrue(menuButton.isMenuShown());
+  // Emulate choosing a menu item by mouse click.
+  var menuItem = menu.menuItems[0];
+  menuItem.selected = true;
+  menuItem.dispatchEvent(new MouseEvent('mouseup', {buttons: 1}));
+  assertFalse(menuButton.isMenuShown());
+  // Focus should be kept on the original place.
+  assertEquals(otherButton, document.activeElement);
+
+  // Case 3: Open menu and activate by keyboard.
+  menuButton.focus();
+  assertEquals(menuButton, document.activeElement);
+  // Open menu
+  menuButton.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
+  assertTrue(menuButton.isMenuShown(), 'menu opened');
+  // Select an item and activate
+  menu.dispatchEvent(new KeyboardEvent('keydown', {key: 'ArrowDown'}));
+  menu.dispatchEvent(new KeyboardEvent('keydown', {key: 'Enter'}));
+  assertFalse(menuButton.isMenuShown(), 'menu closed');
+  // Focus should be still on the menu button.
+  assertEquals(menuButton, document.activeElement);
+}
diff --git a/chrome/test/data/webui/menu_test.html b/chrome/test/data/webui/menu_test.html
index 005dcb6d..5774bb3 100644
--- a/chrome/test/data/webui/menu_test.html
+++ b/chrome/test/data/webui/menu_test.html
@@ -1,228 +1,12 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-/** @type {cr.ui.Menu} */
-var menu;
-
-/**
- * @param {number} x The screenX coord of the mouseup event.
- * @param {number} y The screenY coord of the mouseup event.
- */
-function mouseUpAt(x, y) {
-  var mouseUpEvent = new MouseEvent('mouseup', {
-    bubbles: true,
-    cancelable: true,
-    target: menu,
-    screenX: x,
-    screenY: y,
-  });
-  mouseUpEvent.isTrustedForTesting = true;
-  return menu.dispatchEvent(mouseUpEvent);
-}
-
-function setUp() {
-  menu = new cr.ui.Menu;
-}
-
-function testHandleMouseOver() {
-  var called = false;
-  menu.findMenuItem_ = function() {
-    called = true;
-    return cr.ui.Menu.prototype.findMenuItem_.apply(this, arguments);
-  };
-
-  var over = new MouseEvent('mouseover', {bubbles: true, target: document.body});
-  assertFalse(called);
-  menu.dispatchEvent(over);
-  assertTrue(called);
-}
-
-function testHandleMouseUp() {
-  var realNow = Date.now;
-  Date.now = function() { return 10; };
-
-  menu.show({x: 5, y: 5});
-
-  // Stop mouseups at the same time and position.
-  assertFalse(mouseUpAt(5, 5));
-
-  // Allow mouseups with different positions but the same time.
-  assertTrue(mouseUpAt(50, 50));
-
-  // Alow mouseups with the same position but different times.
-  Date.now = function() { return 1000; };
-  assertTrue(mouseUpAt(5, 5));
-
-  Date.now = realNow;
-}
-
-function testShowViaKeyboardIgnoresMouseUps() {
-  menu.show();
-  assertTrue(mouseUpAt(0, 0));
-}
-
-/**
- * Tests that if the command attributes are spacified, they are copied to the
- * corresponding menuitem.
- */
-function testCommandMenuItem() {
-  // Test 1: The case that the command label is set and other attributes copied.
-  var command = new cr.ui.Command();
-  command.id = 'the-command';
-  command.label = 'CommandLabel';
-  command.disabled = true;
-  command.hidden = true;
-  command.checked = true;
-  document.body.appendChild(command);
-
-  var menuItem = new cr.ui.MenuItem();
-  menuItem.command = '#the-command';
-
-  // Confirms the label is copied from the command.
-  assertEquals('CommandLabel', menuItem.label);
-  // Confirms the attributes are copied from the command.
-  assertEquals(true, menuItem.disabled);
-  assertEquals(true, menuItem.hidden);
-  assertEquals(true, menuItem.checked);
-
-  // Test 2: The case that the command label is not set, and other attributes
-  // have default values.
-  var command2 = new cr.ui.Command();
-  command2.id = 'the-command2';
-  document.body.appendChild(command2);
-
-  var menuItem2 = new cr.ui.MenuItem();
-  menuItem2.label = 'MenuLabel';
-  menuItem2.command = '#the-command2';
-
-  // Confirms the label is not copied, keeping the original label.
-  assertEquals('MenuLabel', menuItem2.label);
-  // Confirms the attributes are copied from the command.
-  assertEquals(false, menuItem2.disabled);
-  assertEquals(false, menuItem2.hidden);
-  assertEquals(false, menuItem2.checked);
-}
-
-/**
- * Mark all menu items other than |hiddenItems| as visible and check that the
- * expected number of separators are visible.
- */
-function runSeparatorTest(items, hiddenItems, expectedSeparators) {
-  for (let item of menu.menuItems) {
-    item.hidden = false;
-  }
-  for (let i of hiddenItems) {
-    items[i].hidden = true;
-  }
-  menu.updateCommands();
-  assertEquals(hiddenItems.length != items.length, menu.hasVisibleItems());
-  assertEquals(expectedSeparators,
-               menu.querySelectorAll('hr:not([hidden])').length);
-
-  // The separators at the ends are always hidden.
-  assertTrue(menu.menuItems[0].hidden);
-  assertTrue(menu.menuItems[6].hidden);
-}
-
-/**
- * Tests that separators are only displayed when there is a visible
- * non-separator item on both sides of it. Further, ensure that multiple
- * separators will not be displayed adjacent to each other.
- */
-function testSeparators() {
-  const menuItems = [];
-  menu.addSeparator();
-  menuItems.push(menu.addMenuItem({label: 'a'}));
-  menu.addSeparator();
-  menuItems.push(menu.addMenuItem({label: 'b'}));
-  menu.addSeparator();
-  menuItems.push(menu.addMenuItem({label: 'c'}));
-  menu.addSeparator();
-
-  runSeparatorTest(menuItems, [0, 1, 2], 0);
-  runSeparatorTest(menuItems, [0, 1], 0);
-  runSeparatorTest(menuItems, [0, 2], 0);
-  runSeparatorTest(menuItems, [1, 2], 0);
-  runSeparatorTest(menuItems, [0], 1);
-  runSeparatorTest(menuItems, [1], 1);
-  runSeparatorTest(menuItems, [2], 1);
-  runSeparatorTest(menuItems, [], 2);
-}
-
-/**
- * Tests that focusSelectedItem() ignores hidden and disabled items.
- */
-function testFocusSelectedItems() {
-  const menu = document.createElement('div');
-  cr.ui.decorate(menu, cr.ui.Menu);
-  const item1 = menu.addMenuItem({label: 'item1'});
-  menu.addSeparator();
-  const item2 = menu.addMenuItem({label: 'item2'});
-  const item3 = menu.addMenuItem({label: 'item3'});
-  document.body.appendChild(menu);
-
-  // Nothing is selected in the menu it should focus the first item.
-  assertEquals(-1, menu.selectedIndex);
-  menu.focusSelectedItem();
-  // Focus the first item.
-  assertEquals(0, menu.selectedIndex);
-
-  // Hide the first item, it should focus the second item.
-  menu.selectedIndex = -1;
-  item1.hidden = true;
-  menu.focusSelectedItem();
-  // Focus the second item, index=1 is the separator.
-  assertEquals(2, menu.selectedIndex);
-
-  // First item is visible but disabled, it should focus the second item.
-  menu.selectedIndex = -1;
-  item1.hidden = false;
-  item1.disabled = true;
-  menu.focusSelectedItem();
-  // Focus the second item, index=1 is the separator.
-  assertEquals(2, menu.selectedIndex);
-
-  // All items are visible but disabled, it should focus the first item.
-  menu.selectedIndex = -1;
-  item1.disabled = true;
-  item2.disabled = true;
-  item3.disabled = true;
-  menu.focusSelectedItem();
-  // Focus the first item.
-  assertEquals(0, menu.selectedIndex);
-
-  // If selectedIndex is already set, focusSelectedItem doesn't change it.
-  assertEquals(0, menu.selectedIndex);
-  item1.disabled = true
-  item2.disabled = false
-  item3.disabled = false
-  menu.focusSelectedItem();
-  // Focus remains in the first item.
-  assertEquals(0, menu.selectedIndex);
-}
-
-/**
- * Tests that cr.ui.MenuItem defaults to tabindex=-1.
- */
-function testMenuItemTabIndex() {
-  // Defaults to -1.
-  const item1 = menu.addMenuItem({label: 'item 1'});
-  assertEquals('-1', item1.getAttribute('tabindex'));
-
-  // Keeps previously set tabindex.
-  const itemDiv = document.createElement('div');
-  itemDiv.setAttribute('tabindex', '0');
-  cr.ui.decorate(itemDiv, cr.ui.MenuItem);
-  assertEquals('0', itemDiv.getAttribute('tabindex'));
-
-  // Separator doesn't get tabindex.
-  menu.addSeparator();
-  const separator = menu.menuItems[menu.menuItems.length - 1];
-  assertTrue(separator.isSeparator());
-  assertFalse(separator.hasAttribute('tabindex'));
-}
-</script>
+<script src="chrome://resources/js/assert.js"></script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/command.js"></script>
+<script src="chrome://resources/js/cr/ui/menu_item.js"></script>
+<script src="chrome://resources/js/cr/ui/menu.js"></script>
+<script src="menu_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/menu_test.js b/chrome/test/data/webui/menu_test.js
new file mode 100644
index 0000000..149fbac
--- /dev/null
+++ b/chrome/test/data/webui/menu_test.js
@@ -0,0 +1,229 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @type {cr.ui.Menu} */
+var menu;
+
+/**
+ * @param {number} x The screenX coord of the mouseup event.
+ * @param {number} y The screenY coord of the mouseup event.
+ */
+function mouseUpAt(x, y) {
+  var mouseUpEvent = new MouseEvent('mouseup', {
+    bubbles: true,
+    cancelable: true,
+    target: menu,
+    screenX: x,
+    screenY: y,
+  });
+  mouseUpEvent.isTrustedForTesting = true;
+  return menu.dispatchEvent(mouseUpEvent);
+}
+
+function setUp() {
+  menu = new cr.ui.Menu;
+}
+
+function testHandleMouseOver() {
+  var called = false;
+  menu.findMenuItem_ = function() {
+    called = true;
+    return cr.ui.Menu.prototype.findMenuItem_.apply(this, arguments);
+  };
+
+  var over =
+      new MouseEvent('mouseover', {bubbles: true, target: document.body});
+  assertFalse(called);
+  menu.dispatchEvent(over);
+  assertTrue(called);
+}
+
+function testHandleMouseUp() {
+  var realNow = Date.now;
+  Date.now = function() {
+    return 10;
+  };
+
+  menu.show({x: 5, y: 5});
+
+  // Stop mouseups at the same time and position.
+  assertFalse(mouseUpAt(5, 5));
+
+  // Allow mouseups with different positions but the same time.
+  assertTrue(mouseUpAt(50, 50));
+
+  // Alow mouseups with the same position but different times.
+  Date.now = function() {
+    return 1000;
+  };
+  assertTrue(mouseUpAt(5, 5));
+
+  Date.now = realNow;
+}
+
+function testShowViaKeyboardIgnoresMouseUps() {
+  menu.show();
+  assertTrue(mouseUpAt(0, 0));
+}
+
+/**
+ * Tests that if the command attributes are spacified, they are copied to the
+ * corresponding menuitem.
+ */
+function testCommandMenuItem() {
+  // Test 1: The case that the command label is set and other attributes copied.
+  var command = new cr.ui.Command();
+  command.id = 'the-command';
+  command.label = 'CommandLabel';
+  command.disabled = true;
+  command.hidden = true;
+  command.checked = true;
+  document.body.appendChild(command);
+
+  var menuItem = new cr.ui.MenuItem();
+  menuItem.command = '#the-command';
+
+  // Confirms the label is copied from the command.
+  assertEquals('CommandLabel', menuItem.label);
+  // Confirms the attributes are copied from the command.
+  assertEquals(true, menuItem.disabled);
+  assertEquals(true, menuItem.hidden);
+  assertEquals(true, menuItem.checked);
+
+  // Test 2: The case that the command label is not set, and other attributes
+  // have default values.
+  var command2 = new cr.ui.Command();
+  command2.id = 'the-command2';
+  document.body.appendChild(command2);
+
+  var menuItem2 = new cr.ui.MenuItem();
+  menuItem2.label = 'MenuLabel';
+  menuItem2.command = '#the-command2';
+
+  // Confirms the label is not copied, keeping the original label.
+  assertEquals('MenuLabel', menuItem2.label);
+  // Confirms the attributes are copied from the command.
+  assertEquals(false, menuItem2.disabled);
+  assertEquals(false, menuItem2.hidden);
+  assertEquals(false, menuItem2.checked);
+}
+
+/**
+ * Mark all menu items other than |hiddenItems| as visible and check that the
+ * expected number of separators are visible.
+ */
+function runSeparatorTest(items, hiddenItems, expectedSeparators) {
+  for (let item of menu.menuItems) {
+    item.hidden = false;
+  }
+  for (let i of hiddenItems) {
+    items[i].hidden = true;
+  }
+  menu.updateCommands();
+  assertEquals(hiddenItems.length !== items.length, menu.hasVisibleItems());
+  assertEquals(
+      expectedSeparators, menu.querySelectorAll('hr:not([hidden])').length);
+
+  // The separators at the ends are always hidden.
+  assertTrue(menu.menuItems[0].hidden);
+  assertTrue(menu.menuItems[6].hidden);
+}
+
+/**
+ * Tests that separators are only displayed when there is a visible
+ * non-separator item on both sides of it. Further, ensure that multiple
+ * separators will not be displayed adjacent to each other.
+ */
+function testSeparators() {
+  const menuItems = [];
+  menu.addSeparator();
+  menuItems.push(menu.addMenuItem({label: 'a'}));
+  menu.addSeparator();
+  menuItems.push(menu.addMenuItem({label: 'b'}));
+  menu.addSeparator();
+  menuItems.push(menu.addMenuItem({label: 'c'}));
+  menu.addSeparator();
+
+  runSeparatorTest(menuItems, [0, 1, 2], 0);
+  runSeparatorTest(menuItems, [0, 1], 0);
+  runSeparatorTest(menuItems, [0, 2], 0);
+  runSeparatorTest(menuItems, [1, 2], 0);
+  runSeparatorTest(menuItems, [0], 1);
+  runSeparatorTest(menuItems, [1], 1);
+  runSeparatorTest(menuItems, [2], 1);
+  runSeparatorTest(menuItems, [], 2);
+}
+
+/**
+ * Tests that focusSelectedItem() ignores hidden and disabled items.
+ */
+function testFocusSelectedItems() {
+  const menu = document.createElement('div');
+  cr.ui.decorate(menu, cr.ui.Menu);
+  const item1 = menu.addMenuItem({label: 'item1'});
+  menu.addSeparator();
+  const item2 = menu.addMenuItem({label: 'item2'});
+  const item3 = menu.addMenuItem({label: 'item3'});
+  document.body.appendChild(menu);
+
+  // Nothing is selected in the menu it should focus the first item.
+  assertEquals(-1, menu.selectedIndex);
+  menu.focusSelectedItem();
+  // Focus the first item.
+  assertEquals(0, menu.selectedIndex);
+
+  // Hide the first item, it should focus the second item.
+  menu.selectedIndex = -1;
+  item1.hidden = true;
+  menu.focusSelectedItem();
+  // Focus the second item, index=1 is the separator.
+  assertEquals(2, menu.selectedIndex);
+
+  // First item is visible but disabled, it should focus the second item.
+  menu.selectedIndex = -1;
+  item1.hidden = false;
+  item1.disabled = true;
+  menu.focusSelectedItem();
+  // Focus the second item, index=1 is the separator.
+  assertEquals(2, menu.selectedIndex);
+
+  // All items are visible but disabled, it should focus the first item.
+  menu.selectedIndex = -1;
+  item1.disabled = true;
+  item2.disabled = true;
+  item3.disabled = true;
+  menu.focusSelectedItem();
+  // Focus the first item.
+  assertEquals(0, menu.selectedIndex);
+
+  // If selectedIndex is already set, focusSelectedItem doesn't change it.
+  assertEquals(0, menu.selectedIndex);
+  item1.disabled = true;
+  item2.disabled = false;
+  item3.disabled = false;
+  menu.focusSelectedItem();
+  // Focus remains in the first item.
+  assertEquals(0, menu.selectedIndex);
+}
+
+/**
+ * Tests that cr.ui.MenuItem defaults to tabindex=-1.
+ */
+function testMenuItemTabIndex() {
+  // Defaults to -1.
+  const item1 = menu.addMenuItem({label: 'item 1'});
+  assertEquals('-1', item1.getAttribute('tabindex'));
+
+  // Keeps previously set tabindex.
+  const itemDiv = document.createElement('div');
+  itemDiv.setAttribute('tabindex', '0');
+  cr.ui.decorate(itemDiv, cr.ui.MenuItem);
+  assertEquals('0', itemDiv.getAttribute('tabindex'));
+
+  // Separator doesn't get tabindex.
+  menu.addSeparator();
+  const separator = menu.menuItems[menu.menuItems.length - 1];
+  assertTrue(separator.isSeparator());
+  assertFalse(separator.hasAttribute('tabindex'));
+}
diff --git a/chrome/test/data/webui/mock_timer_test.html b/chrome/test/data/webui/mock_timer_test.html
index 0a8f68f..f12290d4 100644
--- a/chrome/test/data/webui/mock_timer_test.html
+++ b/chrome/test/data/webui/mock_timer_test.html
@@ -1,135 +1,7 @@
 <!DOCTYPE html>
 <html>
-<head>
-<script src="mock_timer.js"></script>
-</head>
 <body>
-<script>
-
-var mockTimer;
-
-/**
- * Counter class for tallying the number if times a calback is triggered.
- * @constructor
- */
-function ClickCounter() {
-}
-
-ClickCounter.prototype = {
-  /**
-   * Nubmer of times the callback was triggered.
-   * @type{number}
-   * @private
-   */
-  clickCount_: 0,
-
-  /** Increments click count */
-  tick: function() {
-    this.clickCount_++;
-  },
-
-  /**
-   * Creates a callback function that tracks the number of calls.
-   * @return {!Function}
-   */
-  createCallback: function() {
-    var self = this;
-    return function() {
-      self.tick();
-    };
-  },
-
-  /**
-   * Nubmer of times the callback was triggered.
-   * @type {number}
-   */
-  get value() {
-    return this.clickCount_;
-  }
-}
-
-function setUp() {
-  mockTimer = new MockTimer();
-  mockTimer.install();
-}
-
-function tearDown() {
-  mockTimer.uninstall();
-}
-
-function testSetTimeout() {
-  var counter = new ClickCounter();
-  window.setTimeout(counter.createCallback(), 100);
-  assertEquals(0, counter.value);
-  mockTimer.tick(50);
-  assertEquals(0, counter.value);
-  mockTimer.tick(100);
-  assertEquals(1, counter.value);
-  mockTimer.tick(100);
-  assertEquals(1, counter.value);
-}
-
-function testClearTimeout() {
-  var counter = new ClickCounter();
-  var t = window.setTimeout(counter.createCallback(), 100);
-
-  // Verify that clearing a timeout before the elapsed time does not trigger
-  // the callback.
-  window.clearTimeout(t);
-  mockTimer.tick(200);
-  assertEquals(0, counter.value);
-}
-
-function testSetAndClearInterval() {
-  var counter = new ClickCounter();
-  var t = window.setInterval(counter.createCallback(), 100);
-
-  // Verify that callback doesn't fire before elapsed interval.
-  assertEquals(0, counter.value);
-  mockTimer.tick(50);
-
-  // Verify that each elapsed time interval advances the count by 1.
-  assertEquals(0, counter.value);
-  mockTimer.tick(100);
-  assertEquals(1, counter.value);
-  mockTimer.tick(100);
-  assertEquals(2, counter.value);
-  mockTimer.tick(100);
-  assertEquals(3, counter.value);
-
-  // Verify that callbacks stop firing after timer is cleared.
-  window.clearInterval(t);
-  mockTimer.tick(100);
-  assertEquals(3, counter.value);
-}
-
-function testInterleavedTimers() {
-  var results = '';
-  var createCallback = function(response) {
-    var label = response;
-    return function() {
-      results = results + label;
-    };
-  };
-
-  // Verify callbacks are properly interleaved.
-  var t1 = window.setInterval(createCallback('A'), 7);
-  var t2 = window.setInterval(createCallback('B'), 13);
-  mockTimer.tick(30);
-  assertEquals('ABAABA', results);
-  mockTimer.tick(30);
-  assertEquals('ABAABAABAABA', results);
-
-  window.clearInterval(t1);
-  window.setTimeout(createCallback('C'), 11);
-  mockTimer.tick(30);
-  assertEquals('ABAABAABAABABCB', results);
-
-  window.clearInterval(t2);
-  mockTimer.tick(30);
-  assertEquals('ABAABAABAABABCB', results);
-}
-
-</script>
+<script src="mock_timer.js"></script>
+<script src="mock_timer_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/mock_timer_test.js b/chrome/test/data/webui/mock_timer_test.js
new file mode 100644
index 0000000..efee20b
--- /dev/null
+++ b/chrome/test/data/webui/mock_timer_test.js
@@ -0,0 +1,126 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var mockTimer;
+
+/**
+ * Counter class for tallying the number if times a calback is triggered.
+ * @constructor
+ */
+function ClickCounter() {}
+
+ClickCounter.prototype = {
+  /**
+   * Nubmer of times the callback was triggered.
+   * @type{number}
+   * @private
+   */
+  clickCount_: 0,
+
+  /** Increments click count */
+  tick: function() {
+    this.clickCount_++;
+  },
+
+  /**
+   * Creates a callback function that tracks the number of calls.
+   * @return {!Function}
+   */
+  createCallback: function() {
+    var self = this;
+    return function() {
+      self.tick();
+    };
+  },
+
+  /**
+   * Nubmer of times the callback was triggered.
+   * @type {number}
+   */
+  get value() {
+    return this.clickCount_;
+  }
+};
+
+function setUp() {
+  mockTimer = new MockTimer();
+  mockTimer.install();
+}
+
+function tearDown() {
+  mockTimer.uninstall();
+}
+
+function testSetTimeout() {
+  var counter = new ClickCounter();
+  window.setTimeout(counter.createCallback(), 100);
+  assertEquals(0, counter.value);
+  mockTimer.tick(50);
+  assertEquals(0, counter.value);
+  mockTimer.tick(100);
+  assertEquals(1, counter.value);
+  mockTimer.tick(100);
+  assertEquals(1, counter.value);
+}
+
+function testClearTimeout() {
+  var counter = new ClickCounter();
+  var t = window.setTimeout(counter.createCallback(), 100);
+
+  // Verify that clearing a timeout before the elapsed time does not trigger
+  // the callback.
+  window.clearTimeout(t);
+  mockTimer.tick(200);
+  assertEquals(0, counter.value);
+}
+
+function testSetAndClearInterval() {
+  var counter = new ClickCounter();
+  var t = window.setInterval(counter.createCallback(), 100);
+
+  // Verify that callback doesn't fire before elapsed interval.
+  assertEquals(0, counter.value);
+  mockTimer.tick(50);
+
+  // Verify that each elapsed time interval advances the count by 1.
+  assertEquals(0, counter.value);
+  mockTimer.tick(100);
+  assertEquals(1, counter.value);
+  mockTimer.tick(100);
+  assertEquals(2, counter.value);
+  mockTimer.tick(100);
+  assertEquals(3, counter.value);
+
+  // Verify that callbacks stop firing after timer is cleared.
+  window.clearInterval(t);
+  mockTimer.tick(100);
+  assertEquals(3, counter.value);
+}
+
+function testInterleavedTimers() {
+  var results = '';
+  var createCallback = function(response) {
+    var label = response;
+    return function() {
+      results = results + label;
+    };
+  };
+
+  // Verify callbacks are properly interleaved.
+  var t1 = window.setInterval(createCallback('A'), 7);
+  var t2 = window.setInterval(createCallback('B'), 13);
+  mockTimer.tick(30);
+  assertEquals('ABAABA', results);
+  mockTimer.tick(30);
+  assertEquals('ABAABAABAABA', results);
+
+  window.clearInterval(t1);
+  window.setTimeout(createCallback('C'), 11);
+  mockTimer.tick(30);
+  assertEquals('ABAABAABAABABCB', results);
+
+  window.clearInterval(t2);
+  mockTimer.tick(30);
+  assertEquals('ABAABAABAABABCB', results);
+}
diff --git a/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js b/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js
index 75ac454b..d8e5a990 100644
--- a/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js
+++ b/chrome/test/data/webui/nearby_share/shared/nearby_shared_browsertest.js
@@ -17,6 +17,12 @@
   }
 
   /** @override */
+  setUp() {
+    super.setUp();
+    settings.ensureLazyLoaded('chromeos');
+  }
+
+  /** @override */
   get featureList() {
     return {enabled: ['features::kNearbySharing']};
   }
@@ -25,6 +31,7 @@
   get extraLibraries() {
     return super.extraLibraries.concat([
       '../../test_util.js',
+      '../../settings/ensure_lazy_loaded.js',
       'fake_nearby_share_settings.js',
     ]);
   }
diff --git a/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.js b/chrome/test/data/webui/new_tab_page/module_wrapper_test.js
similarity index 95%
rename from chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.js
rename to chrome/test/data/webui/new_tab_page/module_wrapper_test.js
index 7c5d217..90180e39 100644
--- a/chrome/test/data/webui/new_tab_page/modules/module_wrapper_test.js
+++ b/chrome/test/data/webui/new_tab_page/module_wrapper_test.js
@@ -4,7 +4,7 @@
 
 import {$$} from 'chrome://new-tab-page/new_tab_page.js';
 
-suite('NewTabPageModulesModuleWrapperTest', () => {
+suite('NewTabPageModuleWrapperTest', () => {
   /** @type {!ModuleWrapperElement} */
   let moduleWrapper;
 
diff --git a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
index 6d75193..807cb8e 100644
--- a/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
+++ b/chrome/test/data/webui/new_tab_page/new_tab_page_browsertest.js
@@ -192,14 +192,14 @@
 });
 
 // eslint-disable-next-line no-var
-var NewTabPageModulesModuleWrapperTest = class extends NewTabPageBrowserTest {
+var NewTabPageModuleWrapperTest = class extends NewTabPageBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/modules/module_wrapper_test.js';
+    return 'chrome://new-tab-page/test_loader.html?module=new_tab_page/module_wrapper_test.js';
   }
 };
 
-TEST_F('NewTabPageModulesModuleWrapperTest', 'All', function() {
+TEST_F('NewTabPageModuleWrapperTest', 'All', function() {
   mocha.run();
 });
 
diff --git a/chrome/test/data/webui/parse_html_subset_test.html b/chrome/test/data/webui/parse_html_subset_test.html
index b157a46..e05d126 100644
--- a/chrome/test/data/webui/parse_html_subset_test.html
+++ b/chrome/test/data/webui/parse_html_subset_test.html
@@ -4,103 +4,7 @@
 <title>parseHtmlSubset test</title>
 </head>
 <body>
-<script>
-
-function parseAndAssertThrows() {
-  var args = arguments;
-  assertThrows(function() {
-    parseHtmlSubset.apply(null, args);
-  });
-}
-
-function testText() {
-  parseHtmlSubset('');
-  parseHtmlSubset('abc');
-  parseHtmlSubset('&nbsp;');
-}
-
-function testSupportedTags() {
-  parseHtmlSubset('<b>bold</b>');
-  parseHtmlSubset('Some <b>bold</b> text');
-  parseHtmlSubset('Some <strong>strong</strong> text');
-  parseHtmlSubset('<B>bold</B>');
-  parseHtmlSubset('Some <B>bold</B> text');
-  parseHtmlSubset('Some <STRONG>strong</STRONG> text');
-}
-
-function testInvalidTags() {
-  parseAndAssertThrows('<unknown_tag>x</unknown_tag>');
-  parseAndAssertThrows('<style>*{color:red;}</style>');
-  parseAndAssertThrows('<script>alert(1)<' + '/script>');
-}
-
-function testInvalidAttributes() {
-  parseAndAssertThrows('<b onclick="alert(1)">x</b>');
-  parseAndAssertThrows('<b style="color:red">x</b>');
-  parseAndAssertThrows('<b foo>x</b>');
-  parseAndAssertThrows('<b foo=bar></b>');
-}
-
-function testValidAnchors() {
-  parseHtmlSubset('<a href="https://google.com">Google</a>');
-  parseHtmlSubset('<a href="chrome://settings">Google</a>');
-}
-
-function testInvalidAnchorHrefs() {
-  parseAndAssertThrows('<a href="http://google.com">Google</a>');
-  parseAndAssertThrows('<a href="ftp://google.com">Google</a>');
-  parseAndAssertThrows('<a href="http/google.com">Google</a>');
-  parseAndAssertThrows('<a href="javascript:alert(1)">Google</a>');
-  parseAndAssertThrows('<a href="chrome-extension://whurblegarble">Google</a>');
-}
-
-function testInvalidAnchorAttributes() {
-  parseAndAssertThrows('<a name=foo>Google</a>');
-  parseAndAssertThrows(
-      '<a onclick="alert(1)" href="https://google.com">Google</a>');
-  parseAndAssertThrows('<a foo="bar(1)" href="https://google.com">Google</a>');
-}
-
-function testAnchorTarget() {
-  var df = parseHtmlSubset(
-      '<a href="https://google.com" target="_blank">Google</a>');
-  assertEquals('_blank', df.firstChild.target);
-}
-
-function testInvalidTarget() {
-  parseAndAssertThrows('<a href="https://google.com" target="foo">Google</a>');
-}
-
-function testCustomTags() {
-  parseHtmlSubset('<img>', ['IMG']);
-}
-
-function testInvalidCustomTags() {
-  parseAndAssertThrows('a pirate\'s<script>alert();<' + '/script>', ['script']);
-}
-
-function testCustomAttributes() {
-  parseHtmlSubset('<a class="fancy">I\'m fancy!</a>', null,
-      ['class']);
-}
-
-function testInvalidCustomAttributes() {
-  parseAndAssertThrows('<a class="fancy">I\'m fancy!</a>');
-}
-
-function testOnErrorAsync(testDoneCallback) {
-  window.called = false;
-
-  parseAndAssertThrows('<img onerror="window.called = true" src="_.png">');
-  parseAndAssertThrows('<img src="_.png" onerror="window.called = true">');
-
-  window.setTimeout(function() {
-    assertFalse(window.called);
-    testDoneCallback();
-  });
-}
-
-</script>
-
+<script src="chrome://resources/js/parse_html_subset.js"></script>
+<script src="parse_html_subset_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/parse_html_subset_test.js b/chrome/test/data/webui/parse_html_subset_test.js
new file mode 100644
index 0000000..1983fda3
--- /dev/null
+++ b/chrome/test/data/webui/parse_html_subset_test.js
@@ -0,0 +1,101 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function parseAndAssertThrows() {
+  var args = arguments;
+  assertThrows(function() {
+    parseHtmlSubset.apply(null, args);
+  });
+}
+
+function testText() {
+  parseHtmlSubset('');
+  parseHtmlSubset('abc');
+  parseHtmlSubset('&nbsp;');
+}
+
+function testSupportedTags() {
+  parseHtmlSubset('<b>bold</b>');
+  parseHtmlSubset('Some <b>bold</b> text');
+  parseHtmlSubset('Some <strong>strong</strong> text');
+  parseHtmlSubset('<B>bold</B>');
+  parseHtmlSubset('Some <B>bold</B> text');
+  parseHtmlSubset('Some <STRONG>strong</STRONG> text');
+}
+
+function testInvalidTags() {
+  parseAndAssertThrows('<unknown_tag>x</unknown_tag>');
+  parseAndAssertThrows('<style>*{color:red;}</style>');
+  parseAndAssertThrows(
+      '<script>alert(1)<' +
+      '/script>');
+}
+
+function testInvalidAttributes() {
+  parseAndAssertThrows('<b onclick="alert(1)">x</b>');
+  parseAndAssertThrows('<b style="color:red">x</b>');
+  parseAndAssertThrows('<b foo>x</b>');
+  parseAndAssertThrows('<b foo=bar></b>');
+}
+
+function testValidAnchors() {
+  parseHtmlSubset('<a href="https://google.com">Google</a>');
+  parseHtmlSubset('<a href="chrome://settings">Google</a>');
+}
+
+function testInvalidAnchorHrefs() {
+  parseAndAssertThrows('<a href="http://google.com">Google</a>');
+  parseAndAssertThrows('<a href="ftp://google.com">Google</a>');
+  parseAndAssertThrows('<a href="http/google.com">Google</a>');
+  parseAndAssertThrows('<a href="javascript:alert(1)">Google</a>');
+  parseAndAssertThrows('<a href="chrome-extension://whurblegarble">Google</a>');
+}
+
+function testInvalidAnchorAttributes() {
+  parseAndAssertThrows('<a name=foo>Google</a>');
+  parseAndAssertThrows(
+      '<a onclick="alert(1)" href="https://google.com">Google</a>');
+  parseAndAssertThrows('<a foo="bar(1)" href="https://google.com">Google</a>');
+}
+
+function testAnchorTarget() {
+  var df = parseHtmlSubset(
+      '<a href="https://google.com" target="_blank">Google</a>');
+  assertEquals('_blank', df.firstChild.target);
+}
+
+function testInvalidTarget() {
+  parseAndAssertThrows('<a href="https://google.com" target="foo">Google</a>');
+}
+
+function testCustomTags() {
+  parseHtmlSubset('<img>', ['IMG']);
+}
+
+function testInvalidCustomTags() {
+  parseAndAssertThrows(
+      'a pirate\'s<script>alert();<' +
+          '/script>',
+      ['script']);
+}
+
+function testCustomAttributes() {
+  parseHtmlSubset('<a class="fancy">I\'m fancy!</a>', null, ['class']);
+}
+
+function testInvalidCustomAttributes() {
+  parseAndAssertThrows('<a class="fancy">I\'m fancy!</a>');
+}
+
+function testOnErrorAsync(testDoneCallback) {
+  window.called = false;
+
+  parseAndAssertThrows('<img onerror="window.called = true" src="_.png">');
+  parseAndAssertThrows('<img src="_.png" onerror="window.called = true">');
+
+  window.setTimeout(function() {
+    assertFalse(window.called);
+    testDoneCallback();
+  });
+}
diff --git a/chrome/test/data/webui/position_util_test.html b/chrome/test/data/webui/position_util_test.html
index c8abcc4..0dff7628 100644
--- a/chrome/test/data/webui/position_util_test.html
+++ b/chrome/test/data/webui/position_util_test.html
@@ -32,268 +32,9 @@
 <div id=anchor></div>
 <div id=popup></div>
 
-<script>
-
-var anchor = document.getElementById('anchor');
-var popup = document.getElementById('popup');
-var anchorParent = anchor.offsetParent;
-var oldGetBoundingClientRect = anchorParent.getBoundingClientRect;
-var availRect;
-
-function MockRect(w, h) {
-  this.width = w;
-  this.height = h;
-  this.right = this.left + w;
-  this.bottom = this.top + h;
-}
-MockRect.prototype = {
-  left: 0,
-  top: 0
-};
-
-function setUp() {
-  anchor.style.top = '100px';
-  anchor.style.left = '100px';
-  availRect = new MockRect(200, 200);
-  anchorParent.getBoundingClientRect = function() {
-    return availRect;
-  };
-}
-
-function tearDown() {
-  document.documentElement.dir = 'ltr';
-  anchorParent.getBoundingClientRect = oldGetBoundingClientRect;
-}
-
-function testAbovePrimary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-
-  assertEquals('auto', popup.style.top);
-  assertEquals('100px', popup.style.bottom);
-
-  anchor.style.top = '90px';
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-  assertEquals('100px', popup.style.top);
-  assertEquals('auto', popup.style.bottom);
-}
-
-function testBelowPrimary() {
-  // ensure enough below
-  anchor.style.top = '90px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-
-  assertEquals('100px', popup.style.top);
-  assertEquals('auto', popup.style.bottom);
-
-  // ensure not enough below
-  anchor.style.top = '100px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-  assertEquals('auto', popup.style.top);
-  assertEquals('100px', popup.style.bottom);
-}
-
-function testBeforePrimary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('100px', popup.style.right);
-
-  anchor.style.left = '90px';
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testBeforePrimaryRtl() {
-  document.documentElement.dir = 'rtl';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('100px', popup.style.right);
-
-  anchor.style.left = '90px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testAfterPrimary() {
-  // ensure enough to the right
-  anchor.style.left = '90px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-
-  // ensure not enough below
-  anchor.style.left = '100px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-  assertEquals('auto', popup.style.left);
-  assertEquals('100px', popup.style.right);
-}
-
-function testAfterPrimaryRtl() {
-  document.documentElement.dir = 'rtl';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('100px', popup.style.right);
-
-  // ensure not enough below
-  anchor.style.left = '90px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testAboveSecondary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-
-  anchor.style.left = '110px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('80px', popup.style.right);
-}
-
-function testAboveSecondaryRtl() {
-  document.documentElement.dir = 'rtl';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('90px', popup.style.right);
-
-  anchor.style.left = '80px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
-
-  assertEquals('80px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testAboveSecondarySwappedAlign() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE, true);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('90px', popup.style.right);
-
-  anchor.style.left = '80px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE, true);
-
-  assertEquals('80px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testBelowSecondary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-
-  anchor.style.left = '110px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('80px', popup.style.right);
-}
-
-function testBelowSecondaryRtl() {
-  document.documentElement.dir = 'rtl';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('90px', popup.style.right);
-
-  anchor.style.left = '80px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
-
-  assertEquals('80px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testBelowSecondarySwappedAlign() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW, true);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('90px', popup.style.right);
-
-  anchor.style.left = '80px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW, true);
-
-  assertEquals('80px', popup.style.left);
-  assertEquals('auto', popup.style.right);
-}
-
-function testBeforeSecondary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
-
-  assertEquals('100px', popup.style.top);
-  assertEquals('auto', popup.style.bottom);
-
-  anchor.style.top = '110px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
-
-  assertEquals('auto', popup.style.top);
-  assertEquals('80px', popup.style.bottom);
-}
-
-function testAfterSecondary() {
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-
-  assertEquals('100px', popup.style.top);
-  assertEquals('auto', popup.style.bottom);
-
-  anchor.style.top = '110px';
-
-  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
-
-  assertEquals('auto', popup.style.top);
-  assertEquals('80px', popup.style.bottom);
-}
-
-function testPositionAtPoint() {
-  cr.ui.positionPopupAtPoint(100, 100, popup);
-
-  assertEquals('100px', popup.style.left);
-  assertEquals('100px', popup.style.top);
-  assertEquals('auto', popup.style.right);
-  assertEquals('auto', popup.style.bottom);
-
-  cr.ui.positionPopupAtPoint(100, 150, popup);
-
-  assertEquals('100px', popup.style.left);
-  assertEquals('auto', popup.style.top);
-  assertEquals('auto', popup.style.right);
-  assertEquals('50px', popup.style.bottom);
-
-  cr.ui.positionPopupAtPoint(150, 150, popup);
-
-  assertEquals('auto', popup.style.left);
-  assertEquals('auto', popup.style.top);
-  assertEquals('50px', popup.style.right);
-  assertEquals('50px', popup.style.bottom);
-}
-
-</script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui/position_util.js"></script>
+<script src="position_util_test.js"></script>
 
 </body>
 </html>
diff --git a/chrome/test/data/webui/position_util_test.js b/chrome/test/data/webui/position_util_test.js
new file mode 100644
index 0000000..fae85100f
--- /dev/null
+++ b/chrome/test/data/webui/position_util_test.js
@@ -0,0 +1,262 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var anchor = document.getElementById('anchor');
+var popup = document.getElementById('popup');
+var anchorParent = anchor.offsetParent;
+var oldGetBoundingClientRect = anchorParent.getBoundingClientRect;
+var availRect;
+
+function MockRect(w, h) {
+  this.width = w;
+  this.height = h;
+  this.right = this.left + w;
+  this.bottom = this.top + h;
+}
+MockRect.prototype = {
+  left: 0,
+  top: 0
+};
+
+function setUp() {
+  anchor.style.top = '100px';
+  anchor.style.left = '100px';
+  availRect = new MockRect(200, 200);
+  anchorParent.getBoundingClientRect = function() {
+    return availRect;
+  };
+}
+
+function tearDown() {
+  document.documentElement.dir = 'ltr';
+  anchorParent.getBoundingClientRect = oldGetBoundingClientRect;
+}
+
+function testAbovePrimary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+
+  assertEquals('auto', popup.style.top);
+  assertEquals('100px', popup.style.bottom);
+
+  anchor.style.top = '90px';
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+  assertEquals('100px', popup.style.top);
+  assertEquals('auto', popup.style.bottom);
+}
+
+function testBelowPrimary() {
+  // ensure enough below
+  anchor.style.top = '90px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+
+  assertEquals('100px', popup.style.top);
+  assertEquals('auto', popup.style.bottom);
+
+  // ensure not enough below
+  anchor.style.top = '100px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+  assertEquals('auto', popup.style.top);
+  assertEquals('100px', popup.style.bottom);
+}
+
+function testBeforePrimary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('100px', popup.style.right);
+
+  anchor.style.left = '90px';
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testBeforePrimaryRtl() {
+  document.documentElement.dir = 'rtl';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('100px', popup.style.right);
+
+  anchor.style.left = '90px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testAfterPrimary() {
+  // ensure enough to the right
+  anchor.style.left = '90px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+
+  // ensure not enough below
+  anchor.style.left = '100px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+  assertEquals('auto', popup.style.left);
+  assertEquals('100px', popup.style.right);
+}
+
+function testAfterPrimaryRtl() {
+  document.documentElement.dir = 'rtl';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('100px', popup.style.right);
+
+  // ensure not enough below
+  anchor.style.left = '90px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testAboveSecondary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+
+  anchor.style.left = '110px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('80px', popup.style.right);
+}
+
+function testAboveSecondaryRtl() {
+  document.documentElement.dir = 'rtl';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('90px', popup.style.right);
+
+  anchor.style.left = '80px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE);
+
+  assertEquals('80px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testAboveSecondarySwappedAlign() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE, true);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('90px', popup.style.right);
+
+  anchor.style.left = '80px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.ABOVE, true);
+
+  assertEquals('80px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testBelowSecondary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+
+  anchor.style.left = '110px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('80px', popup.style.right);
+}
+
+function testBelowSecondaryRtl() {
+  document.documentElement.dir = 'rtl';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('90px', popup.style.right);
+
+  anchor.style.left = '80px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW);
+
+  assertEquals('80px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testBelowSecondarySwappedAlign() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW, true);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('90px', popup.style.right);
+
+  anchor.style.left = '80px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BELOW, true);
+
+  assertEquals('80px', popup.style.left);
+  assertEquals('auto', popup.style.right);
+}
+
+function testBeforeSecondary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
+
+  assertEquals('100px', popup.style.top);
+  assertEquals('auto', popup.style.bottom);
+
+  anchor.style.top = '110px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.BEFORE);
+
+  assertEquals('auto', popup.style.top);
+  assertEquals('80px', popup.style.bottom);
+}
+
+function testAfterSecondary() {
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+
+  assertEquals('100px', popup.style.top);
+  assertEquals('auto', popup.style.bottom);
+
+  anchor.style.top = '110px';
+
+  cr.ui.positionPopupAroundElement(anchor, popup, cr.ui.AnchorType.AFTER);
+
+  assertEquals('auto', popup.style.top);
+  assertEquals('80px', popup.style.bottom);
+}
+
+function testPositionAtPoint() {
+  cr.ui.positionPopupAtPoint(100, 100, popup);
+
+  assertEquals('100px', popup.style.left);
+  assertEquals('100px', popup.style.top);
+  assertEquals('auto', popup.style.right);
+  assertEquals('auto', popup.style.bottom);
+
+  cr.ui.positionPopupAtPoint(100, 150, popup);
+
+  assertEquals('100px', popup.style.left);
+  assertEquals('auto', popup.style.top);
+  assertEquals('auto', popup.style.right);
+  assertEquals('50px', popup.style.bottom);
+
+  cr.ui.positionPopupAtPoint(150, 150, popup);
+
+  assertEquals('auto', popup.style.left);
+  assertEquals('auto', popup.style.top);
+  assertEquals('50px', popup.style.right);
+  assertEquals('50px', popup.style.bottom);
+}
diff --git a/chrome/test/data/webui/promise_resolver_test.html b/chrome/test/data/webui/promise_resolver_test.html
index 202031d..d2323690 100644
--- a/chrome/test/data/webui/promise_resolver_test.html
+++ b/chrome/test/data/webui/promise_resolver_test.html
@@ -1,44 +1,8 @@
 <!DOCTYPE html>
 <html>
 <body>
-<script>
-
-function testMembersReadOnly() {
-  const resolver = new PromiseResolver;
-  assertThrows(function() { resolver.promise = new Promise; });
-  assertThrows(function() { resolver.resolve = function() {}; });
-  assertThrows(function() { resolver.reject = function() {}; });
-}
-
-function testResolves(done) {
-  const resolver = new PromiseResolver;
-  resolver.promise.then(done);
-  resolver.resolve();
-}
-
-function testRejects(done) {
-  const resolver = new PromiseResolver;
-  resolver.promise.catch(done);
-  resolver.reject();
-}
-
-function testisFulfilled() {
-  const resolver1 = new PromiseResolver;
-  assertFalse(resolver1.isFulfilled);
-  resolver1.resolve();
-  assertTrue(resolver1.isFulfilled);
-
-  const resolver2 = new PromiseResolver;
-  assertFalse(resolver2.isFulfilled);
-  resolver2.resolve(true);
-  assertTrue(resolver2.isFulfilled);
-
-  const resolver3 = new PromiseResolver;
-  assertFalse(resolver3.isFulfilled);
-  resolver3.reject(new Error);
-  assertTrue(resolver3.isFulfilled);
-}
-
-</script>
+<script src="chrome://resources/js/assert.js"></script>
+<script src="chrome://resources/js/promise_resolver.js"></script>
+<script src="promise_resolver_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/promise_resolver_test.js b/chrome/test/data/webui/promise_resolver_test.js
new file mode 100644
index 0000000..3c36794
--- /dev/null
+++ b/chrome/test/data/webui/promise_resolver_test.js
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testMembersReadOnly() {
+  const resolver = new PromiseResolver;
+  assertThrows(function() {
+    resolver.promise = new Promise;
+  });
+  assertThrows(function() {
+    resolver.resolve = function() {};
+  });
+  assertThrows(function() {
+    resolver.reject = function() {};
+  });
+}
+
+function testResolves(done) {
+  const resolver = new PromiseResolver;
+  resolver.promise.then(done);
+  resolver.resolve();
+}
+
+function testRejects(done) {
+  const resolver = new PromiseResolver;
+  resolver.promise.catch(done);
+  resolver.reject();
+}
+
+function testisFulfilled() {
+  const resolver1 = new PromiseResolver;
+  assertFalse(resolver1.isFulfilled);
+  resolver1.resolve();
+  assertTrue(resolver1.isFulfilled);
+
+  const resolver2 = new PromiseResolver;
+  assertFalse(resolver2.isFulfilled);
+  resolver2.resolve(true);
+  assertTrue(resolver2.isFulfilled);
+
+  const resolver3 = new PromiseResolver;
+  assertFalse(resolver3.isFulfilled);
+  resolver3.reject(new Error);
+  assertTrue(resolver3.isFulfilled);
+}
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn
index 75319aa0f..c0a07d3 100644
--- a/chrome/test/data/webui/settings/chromeos/BUILD.gn
+++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -78,6 +78,9 @@
     "os_about_page_tests.js",
     "test_about_page_browser_proxy_chromeos.js",
   ]
-  namespace_rewrites =
-      os_settings_namespace_rewrites + os_test_namespace_rewrites
+  namespace_rewrites = os_settings_namespace_rewrites +
+                       os_test_namespace_rewrites + [
+                         "nearby_share.setNearbyShareSettingsForTesting|setNearbyShareSettingsForTesting",
+                         "nearby_share.FakeNearbyShareSettings|FakeNearbyShareSettings",
+                       ]
 }
diff --git a/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js b/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
index a34ab08a..1d63e60a 100644
--- a/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/ambient_mode_page_test.js
@@ -5,12 +5,10 @@
 // clang-format off
 // #import 'chrome://os-settings/chromeos/os_settings.js';
 
-// #import {AmbientModeTopicSource, AmbientModeTemperatureUnit, AmbientModeBrowserProxyImpl, CrSettingsPrefs, routes, Router} from 'chrome://os-settings/chromeos/os_settings.js';
+// #import {AmbientModeTopicSource, AmbientModeTemperatureUnit, AmbientModeBrowserProxyImpl, CrSettingsPrefs, Router} from 'chrome://os-settings/chromeos/os_settings.js';
 // #import {TestBrowserProxy} from '../../test_browser_proxy.m.js';
 // #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {waitAfterNextRender} from 'chrome://test/test_util.m.js';
 // clang-format on
 
 /**
@@ -94,7 +92,6 @@
   teardown(function() {
     ambientModePage.remove();
     ambientModePhotosPage.remove();
-    settings.Router.getInstance().resetRouteForTesting();
   });
 
   test('toggleAmbientMode', function() {
@@ -159,23 +156,6 @@
     assertEquals(2, topicSourceItems.length);
   });
 
-  test('Deep link to topic sources', async () => {
-    loadTimeData.overrideValues({isDeepLinkingEnabled: true});
-    assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
-
-    const params = new URLSearchParams;
-    params.append('settingId', '502');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.AMBIENT_MODE, params);
-
-    const deepLinkElement =
-        ambientModePage.$$('topic-source-list').$$('topic-source-item');
-    await test_util.waitAfterNextRender(deepLinkElement);
-    assertEquals(
-        deepLinkElement, getDeepActiveElement(),
-        'Topic sources row should be focused for settingId=502.');
-  });
-
   test('hasAlbums', function() {
     ambientModePhotosPage.albums_ = [
       {albumId: 'id0', checked: true, title: 'album0'},
diff --git a/chrome/test/data/webui/settings/chromeos/nearby_share_subpage_tests.js b/chrome/test/data/webui/settings/chromeos/nearby_share_subpage_tests.js
index 8598164..5cf233b7 100644
--- a/chrome/test/data/webui/settings/chromeos/nearby_share_subpage_tests.js
+++ b/chrome/test/data/webui/settings/chromeos/nearby_share_subpage_tests.js
@@ -5,7 +5,8 @@
 // clang-format off
 // #import {assertEquals} from '../../chai_assert.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
-// #import 'chrome://os-settings/chromeos/os_settings.js';
+// #import {setNearbyShareSettingsForTesting} from 'chrome://os-settings/chromeos/os_settings.js';
+// #import {FakeNearbyShareSettings} from '../../nearby_share/shared/fake_nearby_share_settings.m.js';
 // clang-format on
 
 suite('NearbyShare', function() {
@@ -19,6 +20,11 @@
   let toggleRow = null;
 
   setup(function() {
+    /** @type {!nearbyShare.mojom.NearbyShareSettingsInterface} */
+    const fakeSettings = new nearby_share.FakeNearbyShareSettings();
+    fakeSettings.setEnabled(true);
+    nearby_share.setNearbyShareSettingsForTesting(fakeSettings);
+
     PolymerTest.clearBody();
     subpage = document.createElement('settings-nearby-share-subpage');
     subpage.prefs = {
@@ -85,6 +91,19 @@
     assertEquals(newName, subpage.prefs.nearby_sharing.device_name.value);
   });
 
+  test('update visibility shows dialog', function() {
+    // NOTE: all value editing is done and tested in the
+    // nearby-contact-visibility component which is hosted directly on the
+    // dialog. Here we just verify the dialog shows up, it has the component,
+    // and it has a close/action button.
+    subpage.$$('#editVisibilityButton').click();
+    Polymer.dom.flush();
+
+    const dialog = subpage.$$('nearby-share-contact-visibility-dialog');
+    assertTrue(dialog.$$('nearby-contact-visibility') !== null);
+    dialog.$$('.action-button').click();
+  });
+
   test('update data usage preference', function() {
     assertEquals(3, subpage.prefs.nearby_sharing.data_usage.value);
 
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
index 726e2e6..a8cb079 100644
--- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -235,16 +235,11 @@
   get extraLibraries() {
     return super.extraLibraries.concat([
       BROWSER_SETTINGS_PATH + '../test_browser_proxy.js',
-      BROWSER_SETTINGS_PATH + '../test_util.js',
       'ambient_mode_page_test.js',
     ]);
   }
 };
 
-TEST_F('OSSettingsAmbientModePageTest', 'AllJsTests', () => {
-  mocha.run();
-});
-
 // Tests for ambient mode photos page.
 // eslint-disable-next-line no-var
 var OSSettingsAmbientModePhotosPageTest = class extends OSSettingsBrowserTest {
@@ -1065,6 +1060,7 @@
   /** @override */
   get extraLibraries() {
     return super.extraLibraries.concat([
+      '../../nearby_share/shared/fake_nearby_share_settings.js',
       'nearby_share_subpage_tests.js',
     ]);
   }
@@ -1381,7 +1377,6 @@
     return super.extraLibraries.concat([
       '//ui/webui/resources/js/promise_resolver.js',
       BROWSER_SETTINGS_PATH + '../test_browser_proxy.js',
-      BROWSER_SETTINGS_PATH + '../test_util.js',
       BROWSER_SETTINGS_PATH + 'chromeos/test_wallpaper_browser_proxy.js',
       'personalization_page_test.js',
     ]);
diff --git a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js
index c6e06b5..9193e34 100644
--- a/chrome/test/data/webui/settings/chromeos/personalization_page_test.js
+++ b/chrome/test/data/webui/settings/chromeos/personalization_page_test.js
@@ -9,8 +9,6 @@
 // #import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 // #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // #import {TestWallpaperBrowserProxy} from './test_wallpaper_browser_proxy.m.js';
-// #import {getDeepActiveElement} from 'chrome://resources/js/util.m.js';
-// #import {waitAfterNextRender} from 'chrome://test/test_util.m.js';
 // clang-format on
 
 let personalizationPage = null;
@@ -57,7 +55,6 @@
 
   teardown(function() {
     personalizationPage.remove();
-    settings.Router.getInstance().resetRouteForTesting();
   });
 
   test('wallpaperManager', async () => {
@@ -90,22 +87,6 @@
     assertTrue(personalizationPage.$$('#wallpaperButton').disabled);
   });
 
-  test('Deep link to open wallpaper button', async () => {
-    loadTimeData.overrideValues({isDeepLinkingEnabled: true});
-    assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
-
-    const params = new URLSearchParams;
-    params.append('settingId', '500');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.PERSONALIZATION, params);
-
-    const deepLinkElement = personalizationPage.$.wallpaperButton.$$('#icon');
-    await test_util.waitAfterNextRender(deepLinkElement);
-    assertEquals(
-        deepLinkElement, getDeepActiveElement(),
-        'Wallpaper button should be focused for settingId=500.');
-  });
-
   test('changePicture', function() {
     const row = personalizationPage.$.changePictureRow;
     assertTrue(!!row);
@@ -115,28 +96,6 @@
         settings.Router.getInstance().getCurrentRoute());
   });
 
-  test('Deep link to change account picture', async () => {
-    loadTimeData.overrideValues({isDeepLinkingEnabled: true});
-    assertTrue(loadTimeData.getBoolean('isDeepLinkingEnabled'));
-
-    const params = new URLSearchParams;
-    params.append('settingId', '503');
-    settings.Router.getInstance().navigateTo(
-        settings.routes.CHANGE_PICTURE, params);
-
-    await test_util.waitAfterNextRender(personalizationPage);
-
-    const changePicturePage = personalizationPage.$$('settings-change-picture');
-    assertTrue(!!changePicturePage);
-    const deepLinkElement = changePicturePage.$$('#pictureList')
-                                .$$('#selector')
-                                .$$('[class="iron-selected"]');
-    await test_util.waitAfterNextRender(deepLinkElement);
-    assertEquals(
-        deepLinkElement, getDeepActiveElement(),
-        'Account picture elem should be focused for settingId=503.');
-  });
-
   test('ambientMode', function() {
     const isGuest = loadTimeData.getBoolean('isGuest');
     const isAmbientModeEnabled = loadTimeData.getBoolean('isAmbientModeEnabled');
diff --git a/chrome/test/data/webui/splitter_test.html b/chrome/test/data/webui/splitter_test.html
index 0d9dd7a..c1cfca8 100644
--- a/chrome/test/data/webui/splitter_test.html
+++ b/chrome/test/data/webui/splitter_test.html
@@ -4,76 +4,9 @@
 <div id="previous"></div>
 <div id="splitter"></div>
 <div id="next"></div>
-<script>
-function testSplitter_IgnoresRightMouse() {
-  var splitter = document.getElementById('splitter');
-  cr.ui.decorate(splitter, cr.ui.Splitter);
-
-  var downRight = new MouseEvent('mousedown', {button: 1, cancelable: true});
-  assertTrue(splitter.dispatchEvent(downRight));
-  assertFalse(downRight.defaultPrevented);
-
-  var downLeft = new MouseEvent('mousedown', {button: 0, cancelable: true});
-  assertFalse(splitter.dispatchEvent(downLeft));
-  assertTrue(downLeft.defaultPrevented);
-}
-
-function testSplitter_ResizePreviousElement() {
-  var splitter = document.getElementById('splitter');
-  cr.ui.decorate(splitter, cr.ui.Splitter);
-  splitter.resizeNextElement = false;
-
-  var previousElement = document.getElementById('previous');
-  previousElement.style.width = '0px';
-  var beforeWidth = parseFloat(previousElement.style.width);
-
-  var down = new MouseEvent('mousedown',
-      {button: 0, cancelable: true, clientX: 0});
-  splitter.dispatchEvent(down);
-
-  var move = new MouseEvent('mousemove',
-      {button: 0, cancelable: true, clientX: 50});
-  splitter.dispatchEvent(move);
-
-  move = new MouseEvent('mousemove',
-      {button: 0, cancelable: true, clientX: 100});
-  splitter.dispatchEvent(move);
-
-  var up = new MouseEvent('mouseup',
-      {button: 0, cancelable: true, clientX: 100});
-  splitter.dispatchEvent(up);
-
-  var afterWidth = parseFloat(previousElement.style.width);
-  assertEquals(100, afterWidth - beforeWidth);
-}
-
-function testSplitter_ResizeNextElement() {
-  var splitter = document.getElementById('splitter');
-  cr.ui.decorate(splitter, cr.ui.Splitter, true);
-  splitter.resizeNextElement = true;
-  var nextElement = document.getElementById('next');
-  nextElement.style.width = '0px';
-  var beforeWidth = parseFloat(nextElement.style.width);
-
-  var down = new MouseEvent('mousedown',
-      {button: 0, cancelable: true, clientX: 100});
-  splitter.dispatchEvent(down);
-
-  var move = new MouseEvent('mousemove',
-      {button: 0, cancelable: true, clientX: 50});
-  splitter.dispatchEvent(move);
-
-  move = new MouseEvent('mousemove',
-      {button: 0, cancelable: true, clientX: 0});
-  splitter.dispatchEvent(move);
-
-  var up = new MouseEvent('mouseup',
-      {button: 0, cancelable: true, clientX: 0});
-  splitter.dispatchEvent(up);
-
-  var afterWidth = parseFloat(nextElement.style.width);
-  assertEquals(100, afterWidth - beforeWidth);
-}
-</script>
+<script src="chrome://resources/js/cr.js"></script>
+<script src="chrome://resources/js/cr/ui.js"></script>
+<script src="chrome://resources/js/cr/ui/splitter.js"></script>
+<script src="splitter_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/splitter_test.js b/chrome/test/data/webui/splitter_test.js
new file mode 100644
index 0000000..04c4251
--- /dev/null
+++ b/chrome/test/data/webui/splitter_test.js
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testSplitter_IgnoresRightMouse() {
+  var splitter = document.getElementById('splitter');
+  cr.ui.decorate(splitter, cr.ui.Splitter);
+
+  var downRight = new MouseEvent('mousedown', {button: 1, cancelable: true});
+  assertTrue(splitter.dispatchEvent(downRight));
+  assertFalse(downRight.defaultPrevented);
+
+  var downLeft = new MouseEvent('mousedown', {button: 0, cancelable: true});
+  assertFalse(splitter.dispatchEvent(downLeft));
+  assertTrue(downLeft.defaultPrevented);
+}
+
+function testSplitter_ResizePreviousElement() {
+  var splitter = document.getElementById('splitter');
+  cr.ui.decorate(splitter, cr.ui.Splitter);
+  splitter.resizeNextElement = false;
+
+  var previousElement = document.getElementById('previous');
+  previousElement.style.width = '0px';
+  var beforeWidth = parseFloat(previousElement.style.width);
+
+  var down =
+      new MouseEvent('mousedown', {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(down);
+
+  var move =
+      new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 50});
+  splitter.dispatchEvent(move);
+
+  move =
+      new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(move);
+
+  var up =
+      new MouseEvent('mouseup', {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(up);
+
+  var afterWidth = parseFloat(previousElement.style.width);
+  assertEquals(100, afterWidth - beforeWidth);
+}
+
+function testSplitter_ResizeNextElement() {
+  var splitter = document.getElementById('splitter');
+  cr.ui.decorate(splitter, cr.ui.Splitter, true);
+  splitter.resizeNextElement = true;
+  var nextElement = document.getElementById('next');
+  nextElement.style.width = '0px';
+  var beforeWidth = parseFloat(nextElement.style.width);
+
+  var down =
+      new MouseEvent('mousedown', {button: 0, cancelable: true, clientX: 100});
+  splitter.dispatchEvent(down);
+
+  var move =
+      new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 50});
+  splitter.dispatchEvent(move);
+
+  move = new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(move);
+
+  var up = new MouseEvent('mouseup', {button: 0, cancelable: true, clientX: 0});
+  splitter.dispatchEvent(up);
+
+  var afterWidth = parseFloat(nextElement.style.width);
+  assertEquals(100, afterWidth - beforeWidth);
+}
diff --git a/chrome/test/data/webui/util_test.html b/chrome/test/data/webui/util_test.html
index 0f175ae..4463217c 100644
--- a/chrome/test/data/webui/util_test.html
+++ b/chrome/test/data/webui/util_test.html
@@ -4,48 +4,7 @@
 <a id="file" href="file:///path/to/file">File</a>
 <a id="chrome" href="about:chrome">Chrome</a>
 <a href="about:blank"><b id="blank">Click me</b></a>
-<script>
-
-function testQuoteString() {
-  // Basic cases.
-  assertEquals('\"test\"', quoteString('"test"'));
-  assertEquals('\\!\\?', quoteString('!?'));
-  assertEquals('\\(\\._\\.\\) \\( \\:l \\) \\(\\.-\\.\\)',
-      quoteString('(._.) ( :l ) (.-.)'));
-
-  // Using the output as a regex.
-  let re = new RegExp(quoteString('"hello"'), 'gim');
-  let match = re.exec('She said "Hello" loudly');
-  assertEquals(9, match.index);
-
-  re = new RegExp(quoteString('Hello, .*'), 'gim');
-  match = re.exec('Hello, world');
-  assertEquals(null, match);
-}
-
-function testFindAncestor() {
-  const option = document.createElement('option');
-  option.value = 'success';
-
-  const failure = document.createTextNode('is not an option');
-  option.appendChild(failure);
-
-  const select = document.createElement('select');
-  select.appendChild(option);
-
-  const div = document.createElement('div');
-  const root = div.attachShadow({mode: 'open'});
-  root.appendChild(select);
-
-  assertEquals(findAncestor(failure, n => n.nodeName === 'SELECT'), select);
-
-  // findAncestor() only traverses shadow roots (which |div| is outside of) if
-  // |includeShadowHosts| is true. If omitted, |div| shouldn't be found.
-  assertEquals(findAncestor(failure, n => n.nodeName === 'DIV'), null);
-  assertEquals(findAncestor(failure, n => n.nodeName === 'DIV',
-                            /*includeShadowHosts=*/true), div);
-}
-
-</script>
+<script src="chrome://resources/js/util.js"></script>
+<script src="util_test.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/webui/util_test.js b/chrome/test/data/webui/util_test.js
new file mode 100644
index 0000000..a03a3e5
--- /dev/null
+++ b/chrome/test/data/webui/util_test.js
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function testQuoteString() {
+  // Basic cases.
+  assertEquals('\"test\"', quoteString('"test"'));
+  assertEquals('\\!\\?', quoteString('!?'));
+  assertEquals(
+      '\\(\\._\\.\\) \\( \\:l \\) \\(\\.-\\.\\)',
+      quoteString('(._.) ( :l ) (.-.)'));
+
+  // Using the output as a regex.
+  let re = new RegExp(quoteString('"hello"'), 'gim');
+  let match = re.exec('She said "Hello" loudly');
+  assertEquals(9, match.index);
+
+  re = new RegExp(quoteString('Hello, .*'), 'gim');
+  match = re.exec('Hello, world');
+  assertEquals(null, match);
+}
+
+function testFindAncestor() {
+  const option = document.createElement('option');
+  option.value = 'success';
+
+  const failure = document.createTextNode('is not an option');
+  option.appendChild(failure);
+
+  const select = document.createElement('select');
+  select.appendChild(option);
+
+  const div = document.createElement('div');
+  const root = div.attachShadow({mode: 'open'});
+  root.appendChild(select);
+
+  assertEquals(findAncestor(failure, n => n.nodeName === 'SELECT'), select);
+
+  // findAncestor() only traverses shadow roots (which |div| is outside of) if
+  // |includeShadowHosts| is true. If omitted, |div| shouldn't be found.
+  assertEquals(findAncestor(failure, n => n.nodeName === 'DIV'), null);
+  assertEquals(
+      findAncestor(
+          failure, n => n.nodeName === 'DIV',
+          /*includeShadowHosts=*/ true),
+      div);
+}
diff --git a/chrome/test/data/webui/webui_resource_browsertest.cc b/chrome/test/data/webui/webui_resource_browsertest.cc
index 99a8547a3..cb74e62 100644
--- a/chrome/test/data/webui/webui_resource_browsertest.cc
+++ b/chrome/test/data/webui/webui_resource_browsertest.cc
@@ -5,8 +5,10 @@
 #include <vector>
 
 #include "base/path_service.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/test_data_source.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "chrome/test/data/grit/webui_test_resources.h"
@@ -21,6 +23,52 @@
 class WebUIResourceBrowserTest : public InProcessBrowserTest {
  public:
   void SetUpOnMainThread() override {
+    // Setup chrome://test/ data source.
+    content::WebContents* tab =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
+    content::URLDataSource::Add(profile,
+                                std::make_unique<TestDataSource>("webui"));
+  }
+
+  void LoadTestUrl(const std::string& file) {
+    GURL url(std::string("chrome://test/") + file);
+    RunTest(url);
+  }
+
+ private:
+  void RunTest(const GURL& url) {
+    ui_test_utils::NavigateToURL(browser(), url);
+    content::WebContents* web_contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    ASSERT_TRUE(web_contents);
+    EXPECT_TRUE(ExecuteWebUIResourceTest(web_contents, {}));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ArrayDataModelTest) {
+  LoadTestUrl("array_data_model_test.html");
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrTest) {
+  LoadTestUrl("cr_test.html");
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrReloadTest) {
+  LoadTestUrl("cr_reload_test.html");
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, EventTargetTest) {
+  LoadTestUrl("event_target_test.html");
+}
+
+IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, I18nProcessCssTest) {
+  LoadTestUrl("i18n_process_css_test.html");
+}
+
+class WebUIResourceBrowserTestV0 : public InProcessBrowserTest {
+ public:
+  void SetUpOnMainThread() override {
     // Load resources that are only used by browser_tests.
     base::FilePath pak_path;
     ASSERT_TRUE(base::PathService::Get(base::DIR_MODULE, &pak_path));
@@ -31,6 +79,15 @@
     ASSERT_TRUE(embedded_test_server()->Start());
   }
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // TODO(yoichio): This is temporary switch to support chrome internal
+    // components migration from the old web APIs.
+    // After completion of the migration, we should remove this.
+    // See crbug.com/911943 for detail.
+    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
+                                    "HTMLImports");
+  }
+
   // Runs all test functions in |file|, waiting for them to complete.
   void LoadFile(const std::string& file) {
     GURL test_url =
@@ -38,14 +95,6 @@
     RunTest(test_url);
   }
 
-  void LoadResource(int idr) {
-    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-    scoped_refptr<base::RefCountedMemory> resource =
-        bundle.LoadDataResourceBytes(idr);
-    RunTest(GURL(std::string("data:text/html,") +
-                 std::string(resource->front_as<char>(), resource->size())));
-  }
-
   // Queues the library corresponding to |resource_id| for injection into the
   // test. The code injection is performed post-load, so any common test
   // initialization that depends on the library should be placed in a setUp
@@ -67,50 +116,6 @@
   std::vector<int> include_libraries_;
 };
 
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ArrayDataModelTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL);
-  LoadFile("array_data_model_test.html");
-}
-
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  LoadFile("cr_test.html");
-}
-
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CrReloadTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  // Loading cr.js again on purpose to check whether it overwrites the cr
-  // namespace.
-  AddLibrary(IDR_WEBUI_JS_CR);
-  LoadFile("cr_reload_test.html");
-}
-
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, EventTargetTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  LoadFile("event_target_test.html");
-}
-
-IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, I18nProcessCssTest) {
-  LoadResource(IDR_WEBUI_TEST_I18N_PROCESS_CSS_TEST);
-}
-
-class WebUIResourceBrowserTestV0 : public WebUIResourceBrowserTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    // TODO(yoichio): This is temporary switch to support chrome internal
-    // components migration from the old web APIs.
-    // After completion of the migration, we should remove this.
-    // See crbug.com/911943 for detail.
-    command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
-                                    "HTMLImports");
-  }
-};
-
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTestV0, I18nProcessTest) {
   AddLibrary(IDR_WEBUI_JS_LOAD_TIME_DATA);
   AddLibrary(IDR_WEBUI_JS_I18N_TEMPLATE_NO_PROCESS);
@@ -119,135 +124,67 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ListTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_CONTROLLER);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST);
-  LoadFile("list_test.html");
+  LoadTestUrl("list_test.html");
 }
 
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, GridTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_CONTROLLER);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL);
-  // Grid must be the last addition as it depends on list libraries.
-  AddLibrary(IDR_WEBUI_JS_CR_UI_GRID);
-  LoadFile("grid_test.html");
+  LoadTestUrl("grid_test.html");
 }
 #endif
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ListSelectionModelTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL);
-  LoadFile("list_selection_model_test.html");
+  LoadTestUrl("list_selection_model_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ListSingleSelectionModelTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_LIST_SINGLE_SELECTION_MODEL);
-  LoadFile("list_single_selection_model_test.html");
+  LoadTestUrl("list_single_selection_model_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MenuTest) {
-  AddLibrary(IDR_WEBUI_JS_ASSERT);
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_COMMAND);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU);
-  LoadFile("menu_test.html");
+  LoadTestUrl("menu_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MockTimerTest) {
-  LoadFile("mock_timer_test.html");
+  LoadTestUrl("mock_timer_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ParseHtmlSubsetTest) {
-  AddLibrary(IDR_WEBUI_JS_PARSE_HTML_SUBSET);
-  LoadFile("parse_html_subset_test.html");
+  LoadTestUrl("parse_html_subset_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, PositionUtilTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_POSITION_UTIL);
-  LoadFile("position_util_test.html");
+  LoadTestUrl("position_util_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, CommandTest) {
-  AddLibrary(IDR_WEBUI_JS_ASSERT);
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_KEYBOARD_SHORTCUT_LIST);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_COMMAND);
-  LoadFile("command_test.html");
+  LoadTestUrl("command_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, ContextMenuHandlerTest) {
-  AddLibrary(IDR_WEBUI_JS_ASSERT);
-  AddLibrary(IDR_WEBUI_JS_EVENT_TRACKER);
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_EVENT_TARGET);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_POSITION_UTIL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU_BUTTON);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_CONTEXT_MENU_HANDLER);
-  LoadFile("context_menu_handler_test.html");
+  LoadTestUrl("context_menu_handler_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, MenuButtonTest) {
-  AddLibrary(IDR_WEBUI_JS_ASSERT);
-  AddLibrary(IDR_WEBUI_JS_EVENT_TRACKER);
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_POSITION_UTIL);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU_BUTTON);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU_ITEM);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_MENU);
-  LoadFile("menu_button_test.html");
+  LoadTestUrl("menu_button_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, SplitterTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_CR_UI);
-  AddLibrary(IDR_WEBUI_JS_CR_UI_SPLITTER);
-  LoadFile("splitter_test.html");
+  LoadTestUrl("splitter_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, UtilTest) {
-  AddLibrary(IDR_WEBUI_JS_UTIL);
-  LoadFile("util_test.html");
+  LoadTestUrl("util_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, IconTest) {
-  AddLibrary(IDR_WEBUI_JS_CR);
-  AddLibrary(IDR_WEBUI_JS_UTIL);
-  AddLibrary(IDR_WEBUI_JS_ICON);
-  LoadFile("icon_test.html");
+  LoadTestUrl("icon_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, PromiseResolverTest) {
-  AddLibrary(IDR_WEBUI_JS_ASSERT);
-  AddLibrary(IDR_WEBUI_JS_PROMISE_RESOLVER);
-  LoadFile("promise_resolver_test.html");
+  LoadTestUrl("promise_resolver_test.html");
 }
 
 IN_PROC_BROWSER_TEST_F(WebUIResourceBrowserTest, I18nBehaviorTest) {
-  AddLibrary(IDR_WEBUI_JS_LOAD_TIME_DATA);
-  AddLibrary(IDR_WEBUI_JS_PARSE_HTML_SUBSET);
-  AddLibrary(IDR_WEBUI_JS_I18N_BEHAVIOR);
-  LoadFile("i18n_behavior_test.html");
+  LoadTestUrl("i18n_behavior_test.html");
 }
diff --git a/chrome/test/data/webui_test_resources.grd b/chrome/test/data/webui_test_resources.grd
index 438b14d..a488bdd7 100644
--- a/chrome/test/data/webui_test_resources.grd
+++ b/chrome/test/data/webui_test_resources.grd
@@ -12,7 +12,6 @@
       <include name="IDR_MOJO_WEB_UI_CONTROLLER_TEST_HTML" file="webui/mojo/mojo_web_ui_controller_test.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_WEB_UI_TEST_MOJO_JS" file="${root_gen_dir}/chrome/test/data/webui/web_ui_test.mojom.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_WEB_UI_TEST_MOJO_LITE_JS" file="${root_gen_dir}/chrome/test/data/webui/web_ui_test.mojom-lite.js" use_base_dir="false" type="BINDATA"/>
-      <include name="IDR_WEBUI_TEST_I18N_PROCESS_CSS_TEST" file="webui/i18n_process_css_test.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
     </includes>
   </release>
 </grit>
diff --git a/chromeos/components/camera_app_ui/resources/BUILD.gn b/chromeos/components/camera_app_ui/resources/BUILD.gn
index d68b5d6..259ea13 100644
--- a/chromeos/components/camera_app_ui/resources/BUILD.gn
+++ b/chromeos/components/camera_app_ui/resources/BUILD.gn
@@ -26,6 +26,7 @@
     ":chrome_camera_app_js_mojo",
     ":chrome_camera_app_js_views",
     ":chrome_camera_app_js_views_camera",
+    ":chrome_camera_app_js_views_camera_mode",
     ":chrome_camera_app_mojo_generated",
     ":chrome_camera_app_sounds",
     ":chrome_camera_app_views",
@@ -98,6 +99,7 @@
     "src/js/chrome_util.js",
     "src/js/error.js",
     "src/js/gallerybutton.js",
+    "src/js/init.js",
     "src/js/intent.js",
     "src/js/main.js",
     "src/js/metrics.js",
@@ -189,10 +191,8 @@
 copy("chrome_camera_app_js_views_camera") {
   sources = [
     "src/js/views/camera/layout.js",
-    "src/js/views/camera/modes.js",
     "src/js/views/camera/options.js",
     "src/js/views/camera/preview.js",
-    "src/js/views/camera/recordtime.js",
     "src/js/views/camera/review_result.js",
     "src/js/views/camera/timertick.js",
   ]
@@ -200,6 +200,20 @@
   outputs = [ "$out_camera_app_dir/js/views/camera/{{source_file_part}}" ]
 }
 
+copy("chrome_camera_app_js_views_camera_mode") {
+  sources = [
+    "src/js/views/camera/mode/index.js",
+    "src/js/views/camera/mode/mode_base.js",
+    "src/js/views/camera/mode/photo.js",
+    "src/js/views/camera/mode/portrait.js",
+    "src/js/views/camera/mode/record_time.js",
+    "src/js/views/camera/mode/square.js",
+    "src/js/views/camera/mode/video.js",
+  ]
+
+  outputs = [ "$out_camera_app_dir/js/views/camera/mode/{{source_file_part}}" ]
+}
+
 copy("chrome_camera_app_sounds") {
   sources = [
     "src/sounds/record_end.ogg",
diff --git a/chromeos/components/camera_app_ui/resources/camera_app_resources.grd b/chromeos/components/camera_app_ui/resources/camera_app_resources.grd
index 53089d8..cf8878e8 100644
--- a/chromeos/components/camera_app_ui/resources/camera_app_resources.grd
+++ b/chromeos/components/camera_app_ui/resources/camera_app_resources.grd
@@ -36,6 +36,7 @@
       <structure name="IDR_CAMERA_FILE_UTIL_JS" file="src/js/models/file_util.js" type="chrome_html" />
       <structure name="IDR_CAMERA_GALLERYBUTTON_JS" file="src/js/gallerybutton.js" type="chrome_html" />
       <structure name="IDR_CAMERA_IMAGECAPTURE_JS" file="src/js/mojo/image_capture.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_INIT_JS" file="src/js/init.js" type="chrome_html" />
       <structure name="IDR_CAMERA_INTENT_JS" file="src/js/intent.js" type="chrome_html" />
       <structure name="IDR_CAMERA_LAYOUT_JS" file="src/js/views/camera/layout.js" type="chrome_html" />
       <structure name="IDR_CAMERA_MAIN_CSS" file="src/css/main.css" type="chrome_html" />
@@ -43,7 +44,13 @@
       <structure name="IDR_CAMERA_MAIN_JS" file="src/js/main.js" type="chrome_html" />
       <structure name="IDR_CAMERA_MANIFEST" file="manifest.json" type="chrome_html" />
       <structure name="IDR_CAMERA_METRICS_JS" file="src/js/metrics.js" type="chrome_html" />
-      <structure name="IDR_CAMERA_MODES_JS" file="src/js/views/camera/modes.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_MODE_BASE_JS" file="src/js/views/camera/mode/mode_base.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_INDEX_JS" file="src/js/views/camera/mode/index.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_PHOTO_JS" file="src/js/views/camera/mode/photo.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_PORTRAIT_JS" file="src/js/views/camera/mode/portrait.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_RECORD_TIME_JS" file="src/js/views/camera/mode/record_time.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_SQUARE_JS" file="src/js/views/camera/mode/square.js" type="chrome_html" />
+      <structure name="IDR_CAMERA_MODE_VIDEO_JS" file="src/js/views/camera/mode/video.js" type="chrome_html" />
       <structure name="IDR_CAMERA_MP4_VIDEO_PROCESSOR_JS" file="src/js/models/mp4_video_processor.js" type="chrome_html" />
       <structure name="IDR_CAMERA_NATIVE_FILE_SYSTEM_ENTRY_JS" file="src/js/models/native_file_system_entry.js" type="chrome_html" />
       <structure name="IDR_CAMERA_NAV_JS" file="src/js/nav.js" type="chrome_html" />
@@ -52,7 +59,6 @@
       <structure name="IDR_CAMERA_PERF_JS" file="src/js/perf.js" type="chrome_html" />
       <structure name="IDR_CAMERA_PREVIEW_JS" file="src/js/views/camera/preview.js" type="chrome_html" />
       <structure name="IDR_CAMERA_PWA_HTML" file="pwa.html" type="chrome_html" />
-      <structure name="IDR_CAMERA_RECORDTIME_JS" file="src/js/views/camera/recordtime.js" type="chrome_html" />
       <structure name="IDR_CAMERA_RESULT_SAVER_JS" file="src/js/models/result_saver.js" type="chrome_html" />
       <structure name="IDR_CAMERA_REVIEW_RESULT_JS" file="src/js/views/camera/review_result.js" type="chrome_html" />
       <structure name="IDR_CAMERA_SETTINGS_JS" file="src/js/views/settings.js" type="chrome_html" />
diff --git a/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn b/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
index 380713e4..38cfe5f 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
+++ b/chromeos/components/camera_app_ui/resources/src/js/BUILD.gn
@@ -29,6 +29,7 @@
     "device/device_info_updater.js",
     "error.js",
     "gallerybutton.js",
+    "init.js",
     "intent.js",
     "lib/comlink.js",
     "lib/ffmpeg.js",
@@ -58,10 +59,15 @@
     "util.js",
     "views/camera.js",
     "views/camera/layout.js",
-    "views/camera/modes.js",
+    "views/camera/mode/index.js",
+    "views/camera/mode/mode_base.js",
+    "views/camera/mode/photo.js",
+    "views/camera/mode/portrait.js",
+    "views/camera/mode/record_time.js",
+    "views/camera/mode/square.js",
+    "views/camera/mode/video.js",
     "views/camera/options.js",
     "views/camera/preview.js",
-    "views/camera/recordtime.js",
     "views/camera/review_result.js",
     "views/camera/timertick.js",
     "views/camera_intent.js",
diff --git a/chromeos/components/camera_app_ui/resources/src/js/init.js b/chromeos/components/camera_app_ui/resources/src/js/init.js
new file mode 100644
index 0000000..8617431d
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/init.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+document.addEventListener('DOMContentLoaded', () => {
+  const mainScript = document.createElement('script');
+  mainScript.setAttribute('type', 'module');
+  mainScript.setAttribute('src', '../js/main.js');
+  document.head.appendChild(mainScript);
+});
diff --git a/chromeos/components/camera_app_ui/resources/src/js/main.js b/chromeos/components/camera_app_ui/resources/src/js/main.js
index 38b1c81..aa735f7 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/main.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/main.js
@@ -261,7 +261,7 @@
 /**
  * Creates the App object and starts camera stream.
  */
-document.addEventListener('DOMContentLoaded', async () => {
+(async () => {
   if (instance !== null) {
     return;
   }
@@ -319,4 +319,4 @@
   instance = new App(
       /** @type {!BackgroundOps} */ (bgOps));
   await instance.start();
-});
+})();
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
index da96f562..119e5fe 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera.js
@@ -29,12 +29,12 @@
 import * as util from '../util.js';
 
 import {Layout} from './camera/layout.js';
-import {
+import {   // eslint-disable-line no-unused-vars
   Modes,
-  PhotoResult,  // eslint-disable-line no-unused-vars
+  PhotoHandler,  // eslint-disable-line no-unused-vars
   Video,
-  VideoResult,  // eslint-disable-line no-unused-vars
-} from './camera/modes.js';
+  VideoHandler,  // eslint-disable-line no-unused-vars
+} from './camera/mode/index.js';
 import {Options} from './camera/options.js';
 import {Preview} from './camera/preview.js';
 import * as timertick from './camera/timertick.js';
@@ -55,6 +55,8 @@
 
 /**
  * Camera-view controller.
+ * @implements {VideoHandler}
+ * @implements {PhotoHandler}
  */
 export class Camera extends View {
   /**
@@ -123,13 +125,6 @@
      */
     this.activeDeviceId_ = null;
 
-    const createVideoSaver = async () => resultSaver.startSaveVideo();
-
-    const playShutterEffect = () => {
-      sound.play('#sound-shutter');
-      util.animateOnce(this.preview_.video);
-    };
-
     /**
      * Modes for the camera.
      * @type {!Modes}
@@ -137,9 +132,7 @@
      */
     this.modes_ = new Modes(
         this.defaultMode_, photoPreferrer, videoPreferrer,
-        this.start.bind(this), this.doSavePhoto_.bind(this), createVideoSaver,
-        this.doSaveVideo_.bind(this), playShutterEffect,
-        () => this.preview_.toImage());
+        this.start.bind(this), this, this);
 
     /**
      * @type {!Facing}
@@ -389,13 +382,9 @@
   }
 
   /**
-   * Handles captured photo result.
-   * @param {!PhotoResult} result Captured photo result.
-   * @param {string} name Name of the photo result to be saved as.
-   * @return {!Promise} Promise for the operation.
-   * @protected
+   * @override
    */
-  async doSavePhoto_({resolution, blob, isVideoSnapshot = false}, name) {
+  async handleResultPhoto({resolution, blob, isVideoSnapshot}, name) {
     metrics.sendCaptureEvent({
       facing: this.facingMode_,
       resolution,
@@ -411,12 +400,31 @@
   }
 
   /**
-   * Handles captured video result.
-   * @param {!VideoResult} result Captured video result.
-   * @return {!Promise} Promise for the operation.
-   * @protected
+   * @override
    */
-  async doSaveVideo_({resolution, duration, videoSaver, everPaused}) {
+  createVideoSaver() {
+    return this.resultSaver_.startSaveVideo();
+  }
+
+  /**
+   * @override
+   */
+  playShutterEffect() {
+    sound.play('#sound-shutter');
+    util.animateOnce(this.preview_.video);
+  }
+
+  /**
+   * @override
+   */
+  getPreviewFrame() {
+    return this.preview_.toImage();
+  }
+
+  /**
+   * @override
+   */
+  async handleResultVideo({resolution, duration, videoSaver, everPaused}) {
     metrics.sendCaptureEvent({
       facing: this.facingMode_,
       duration,
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/index.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/index.js
new file mode 100644
index 0000000..39844b4
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/index.js
@@ -0,0 +1,453 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert, assertInstanceof} from '../../../chrome_util.js';
+import {
+  CaptureCandidate,           // eslint-disable-line no-unused-vars
+  ConstraintsPreferrer,       // eslint-disable-line no-unused-vars
+  PhotoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
+  VideoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
+} from '../../../device/constraints_preferrer.js';
+// eslint-disable-next-line no-unused-vars
+import {DeviceOperator} from '../../../mojo/device_operator.js';
+import * as state from '../../../state.js';
+import {
+  Facing,
+  Mode,
+  Resolution,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+import * as util from '../../../util.js';
+
+import {ModeBase} from './mode_base.js';  // eslint-disable-line no-unused-vars
+import {
+  Photo,
+  PhotoHandler,
+  PhotoResult,
+} from './photo.js';
+import {Portrait} from './portrait.js';
+import {Square} from './square.js';
+import {
+  Video,
+  VideoHandler,
+  VideoResult,
+} from './video.js';
+
+export {PhotoHandler, PhotoResult, Video, VideoHandler, VideoResult};
+
+/**
+ * Callback to trigger mode switching.
+ * return {!Promise}
+ * @typedef {function(): !Promise}
+ */
+export let DoSwitchMode;
+
+/* eslint-disable no-unused-vars */
+
+/**
+ * The abstract interface for the mode configuration.
+ * @interface
+ */
+class ModeConfig {
+  /**
+   * Factory function to create capture object for this mode.
+   * @return {!ModeBase}
+   * @abstract
+   */
+  captureFactory() {}
+
+  /**
+   * @param {?string} deviceId
+   * @return {!Promise<boolean>} Resolves to boolean indicating whether the mode
+   *     is supported by video device with specified device id.
+   * @abstract
+   */
+  async isSupported(deviceId) {}
+
+  /**
+   * Get stream constraints for HALv1 of this mode.
+   * @param {?string} deviceId
+   * @return {!Array<!MediaStreamConstraints>}
+   * @abstract
+   */
+  getV1Constraints(deviceId) {}
+
+  /* eslint-disable getter-return */
+
+  /**
+   * HALv3 constraints preferrer for this mode.
+   * @return {!ConstraintsPreferrer}
+   * @abstract
+   */
+  get constraintsPreferrer() {}
+
+  /**
+   * Mode to be fallbacked to when fail to configure this mode.
+   * @return {!Mode}
+   * @abstract
+   */
+  get nextMode() {}
+
+  /**
+   * Capture intent of this mode.
+   * @return {!cros.mojom.CaptureIntent}
+   * @abstract
+   */
+  get captureIntent() {}
+
+  /* eslint-enable getter-return */
+}
+
+/* eslint-enable no-unused-vars */
+
+/**
+ * Mode controller managing capture sequence of different camera mode.
+ */
+export class Modes {
+  /**
+   * @param {!Mode} defaultMode Default mode to be switched to.
+   * @param {!PhotoConstraintsPreferrer} photoPreferrer
+   * @param {!VideoConstraintsPreferrer} videoPreferrer
+   * @param {!DoSwitchMode} doSwitchMode
+   * @param {!PhotoHandler} photoHandler
+   * @param {!VideoHandler} videoHandler
+   */
+  constructor(
+      defaultMode, photoPreferrer, videoPreferrer, doSwitchMode, photoHandler,
+      videoHandler) {
+    /**
+     * @type {!DoSwitchMode}
+     * @private
+     */
+    this.doSwitchMode_ = doSwitchMode;
+
+    /**
+     * Capture controller of current camera mode.
+     * @type {?ModeBase}
+     */
+    this.current = null;
+
+    /**
+     * Stream of current mode.
+     * @type {?MediaStream}
+     * @private
+     */
+    this.stream_ = null;
+
+    /**
+     * Camera facing of current mode.
+     * @type {!Facing}
+     * @private
+     */
+    this.facing_ = Facing.UNKNOWN;
+
+    /**
+     * @type {!HTMLElement}
+     * @private
+     */
+    this.modesGroup_ =
+        assertInstanceof(document.querySelector('#modes-group'), HTMLElement);
+
+    /**
+     * @type {?Resolution}
+     * @private
+     */
+    this.captureResolution_ = null;
+
+    /**
+     * Returns a set of available constraints for HALv1 device.
+     * @param {boolean} videoMode Is getting constraints for video mode.
+     * @param {?string} deviceId Id of video device.
+     * @return {!Array<!MediaStreamConstraints>} Result of
+     *     constraints-candidates.
+     */
+    const getV1Constraints = function(videoMode, deviceId) {
+      const /** !Array<!MediaTrackConstraints> */ baseConstraints = [
+        {
+          aspectRatio: {ideal: videoMode ? 1.7777777778 : 1.3333333333},
+          width: {min: 1280},
+          frameRate: {min: 20, ideal: 30},
+        },
+        {
+          width: {min: 640},
+          frameRate: {min: 20, ideal: 30},
+        },
+      ];
+      return baseConstraints.map((constraint) => {
+        if (deviceId) {
+          constraint.deviceId = {exact: deviceId};
+        } else {
+          // HALv1 devices are unable to know facing before stream
+          // configuration, deviceId is set to null for requesting camera with
+          // default facing.
+          constraint.facingMode = {exact: util.getDefaultFacing()};
+        }
+        return {
+          audio: videoMode ? {echoCancellation: false} : false,
+          video: constraint,
+        };
+      });
+    };
+
+    /**
+     * Mode classname and related functions and attributes.
+     * @type {!Object<!Mode, !ModeConfig>}
+     * @private
+     */
+    this.allModes_ = {
+      [Mode.VIDEO]: {
+        captureFactory: () => new Video(
+            assertInstanceof(this.stream_, MediaStream), this.facing_,
+            videoHandler),
+        isSupported: async () => true,
+        constraintsPreferrer: videoPreferrer,
+        getV1Constraints: getV1Constraints.bind(this, true),
+        nextMode: Mode.PHOTO,
+        captureIntent: cros.mojom.CaptureIntent.VIDEO_RECORD,
+      },
+      [Mode.PHOTO]: {
+        captureFactory: () => new Photo(
+            assertInstanceof(this.stream_, MediaStream), this.facing_,
+            this.captureResolution_, photoHandler),
+        isSupported: async () => true,
+        constraintsPreferrer: photoPreferrer,
+        getV1Constraints: getV1Constraints.bind(this, false),
+        nextMode: Mode.SQUARE,
+        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
+      },
+      [Mode.SQUARE]: {
+        captureFactory: () => new Square(
+            assertInstanceof(this.stream_, MediaStream), this.facing_,
+            this.captureResolution_, photoHandler),
+        isSupported: async () => true,
+        constraintsPreferrer: photoPreferrer,
+        getV1Constraints: getV1Constraints.bind(this, false),
+        nextMode: Mode.PHOTO,
+        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
+      },
+      [Mode.PORTRAIT]: {
+        captureFactory: () => new Portrait(
+            assertInstanceof(this.stream_, MediaStream), this.facing_,
+            this.captureResolution_, photoHandler),
+        isSupported: async (deviceId) => {
+          if (deviceId === null) {
+            return false;
+          }
+          const deviceOperator = await DeviceOperator.getInstance();
+          if (deviceOperator === null) {
+            return false;
+          }
+          return await deviceOperator.isPortraitModeSupported(deviceId);
+        },
+        constraintsPreferrer: photoPreferrer,
+        getV1Constraints: getV1Constraints.bind(this, false),
+        nextMode: Mode.PHOTO,
+        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
+      },
+    };
+
+    document.querySelectorAll('.mode-item>input').forEach((element) => {
+      element.addEventListener('click', (event) => {
+        if (!state.get(state.State.STREAMING) ||
+            state.get(state.State.TAKING)) {
+          event.preventDefault();
+        }
+      });
+      element.addEventListener('change', async (event) => {
+        if (element.checked) {
+          const mode = element.dataset.mode;
+          this.updateModeUI_(mode);
+          state.set(state.State.MODE_SWITCHING, true);
+          const isSuccess = await this.doSwitchMode_();
+          state.set(state.State.MODE_SWITCHING, false, {hasError: !isSuccess});
+        }
+      });
+    });
+
+    [state.State.EXPERT, state.State.SAVE_METADATA].forEach(
+        (/** !state.State */ s) => {
+          state.addObserver(s, this.updateSaveMetadata_.bind(this));
+        });
+
+    // Set default mode when app started.
+    this.updateModeUI_(defaultMode);
+  }
+
+  /**
+   * @return {!Array<!Mode>}
+   * @private
+   */
+  get allModeNames_() {
+    return Object.keys(this.allModes_);
+  }
+
+  /**
+   * Updates state of mode related UI to the target mode.
+   * @param {!Mode} mode Mode to be toggled.
+   * @private
+   */
+  updateModeUI_(mode) {
+    this.allModeNames_.forEach((m) => state.set(m, m === mode));
+    const element =
+        document.querySelector(`.mode-item>input[data-mode=${mode}]`);
+    element.checked = true;
+    const wrapper = element.parentElement;
+    let scrollTop = wrapper.offsetTop - this.modesGroup_.offsetHeight / 2 +
+        wrapper.offsetHeight / 2;
+    // Make photo mode scroll slightly upper so that the third mode item falls
+    // in blur area: crbug.com/988869
+    if (mode === Mode.PHOTO) {
+      scrollTop -= 16;
+    }
+    this.modesGroup_.scrollTo({
+      left: 0,
+      top: scrollTop,
+      behavior: 'smooth',
+    });
+  }
+
+  /**
+   * Gets all mode candidates. Desired trying sequence of candidate modes is
+   * reflected in the order of the returned array.
+   * @return {!Array<!Mode>} Mode candidates to be tried out.
+   */
+  getModeCandidates() {
+    const tried = {};
+    const /** !Array<!Mode> */ results = [];
+    let mode = this.allModeNames_.find(state.get);
+    assert(mode !== undefined);
+    while (!tried[mode]) {
+      tried[mode] = true;
+      results.push(mode);
+      mode = this.allModes_[mode].nextMode;
+    }
+    return results;
+  }
+
+  /**
+   * Gets all available capture resolution and its corresponding preview
+   * constraints for the given mode.
+   * @param {!Mode} mode
+   * @param {string} deviceId
+   * @return {!Array<!CaptureCandidate>}
+   */
+  getResolutionCandidates(mode, deviceId) {
+    return this.allModes_[mode].constraintsPreferrer.getSortedCandidates(
+        deviceId);
+  }
+
+  /**
+   * Gets capture resolution and its corresponding preview constraints for the
+   * given mode on camera HALv1 device.
+   * @param {!Mode} mode
+   * @param {?string} deviceId
+   * @return {!Array<!CaptureCandidate>}
+   */
+  getResolutionCandidatesV1(mode, deviceId) {
+    const previewCandidates = this.allModes_[mode].getV1Constraints(deviceId);
+    return [{resolution: null, previewCandidates}];
+  }
+
+  /**
+   * Gets capture intent for the given mode.
+   * @param {!Mode} mode
+   * @return {!cros.mojom.CaptureIntent} Capture intent for the given mode.
+   */
+  getCaptureIntent(mode) {
+    return this.allModes_[mode].captureIntent;
+  }
+
+  /**
+   * Gets supported modes for video device of given device id.
+   * @param {?string} deviceId Device id of the video device.
+   * @return {!Promise<!Array<!Mode>>} All supported mode for
+   *     the video device.
+   */
+  async getSupportedModes(deviceId) {
+    const /** !Array<!Mode> */ supportedModes = [];
+    for (const mode of this.allModeNames_) {
+      const obj = this.allModes_[mode];
+      if (await obj.isSupported(deviceId)) {
+        supportedModes.push(mode);
+      }
+    }
+    return supportedModes;
+  }
+
+  /**
+   * Updates mode selection UI according to given device id.
+   * @param {?string} deviceId
+   * @return {!Promise}
+   */
+  async updateModeSelectionUI(deviceId) {
+    const supportedModes = await this.getSupportedModes(deviceId);
+    document.querySelectorAll('.mode-item').forEach((element) => {
+      const radio = element.querySelector('input[type=radio]');
+      element.classList.toggle(
+          'hide', !supportedModes.includes(radio.dataset.mode));
+    });
+    this.modesGroup_.classList.toggle('scrollable', supportedModes.length > 3);
+    this.modesGroup_.classList.remove('hide');
+  }
+
+  /**
+   * Creates and updates new current mode object.
+   * @param {!Mode} mode Classname of mode to be updated.
+   * @param {!MediaStream} stream Stream of the new switching mode.
+   * @param {!Facing} facing Camera facing of the current mode.
+   * @param {?string} deviceId Device id of currently working video device.
+   * @param {?Resolution} captureResolution Capturing resolution width and
+   *     height.
+   * @return {!Promise}
+   */
+  async updateMode(mode, stream, facing, deviceId, captureResolution) {
+    if (this.current !== null) {
+      await this.current.stopCapture();
+    }
+    this.updateModeUI_(mode);
+    this.stream_ = stream;
+    this.facing_ = facing;
+    this.captureResolution_ = captureResolution;
+    this.current = this.allModes_[mode].captureFactory();
+    if (deviceId && this.captureResolution_) {
+      this.allModes_[mode].constraintsPreferrer.updateValues(
+          deviceId, stream, facing, this.captureResolution_);
+    }
+    await this.updateSaveMetadata_();
+  }
+
+  /**
+   * Checks whether to save image metadata or not.
+   * @return {!Promise} Promise for the operation.
+   * @private
+   */
+  async updateSaveMetadata_() {
+    if (state.get(state.State.EXPERT) && state.get(state.State.SAVE_METADATA)) {
+      await this.enableSaveMetadata_();
+    } else {
+      await this.disableSaveMetadata_();
+    }
+  }
+
+  /**
+   * Enables save metadata of subsequent photos in the current mode.
+   * @return {!Promise} Promise for the operation.
+   * @private
+   */
+  async enableSaveMetadata_() {
+    if (this.current !== null) {
+      await this.current.addMetadataObserver();
+    }
+  }
+
+  /**
+   * Disables save metadata of subsequent photos in the current mode.
+   * @return {!Promise} Promise for the operation.
+   * @private
+   */
+  async disableSaveMetadata_() {
+    if (this.current !== null) {
+      await this.current.removeMetadataObserver();
+    }
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/mode_base.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/mode_base.js
new file mode 100644
index 0000000..0ae18df
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/mode_base.js
@@ -0,0 +1,97 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {
+  Facing,      // eslint-disable-line no-unused-vars
+  Resolution,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+
+/**
+ * Base class for controlling capture sequence in different camera modes.
+ * @abstract
+ */
+export class ModeBase {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {?Resolution} captureResolution Capturing resolution width and
+   *     height.
+   */
+  constructor(stream, facing, captureResolution) {
+    /**
+     * Stream of current mode.
+     * @type {!MediaStream}
+     * @protected
+     */
+    this.stream_ = stream;
+
+    /**
+     * Camera facing of current mode.
+     * @type {!Facing}
+     * @protected
+     */
+    this.facing_ = facing;
+
+    /**
+     * Capture resolution. May be null on device not support of setting
+     * resolution.
+     * @type {?Resolution}
+     * @protected
+     */
+    this.captureResolution_ = captureResolution;
+
+    /**
+     * Promise for ongoing capture operation.
+     * @type {?Promise}
+     * @private
+     */
+    this.capture_ = null;
+  }
+
+  /**
+   * Initiates video/photo capture operation.
+   * @return {!Promise} Promise for ongoing capture operation.
+   */
+  startCapture() {
+    if (this.capture_ === null) {
+      this.capture_ = this.start_().finally(() => this.capture_ = null);
+    }
+    return this.capture_;
+  }
+
+  /**
+   * Stops the ongoing capture operation.
+   * @return {!Promise} Promise for ongoing capture operation.
+   */
+  async stopCapture() {
+    this.stop_();
+    return await this.capture_;
+  }
+
+  /**
+   * Adds an observer to save image metadata.
+   * @return {!Promise} Promise for the operation.
+   */
+  async addMetadataObserver() {}
+
+  /**
+   * Remove the observer that saves metadata.
+   * @return {!Promise} Promise for the operation.
+   */
+  async removeMetadataObserver() {}
+
+  /**
+   * Initiates video/photo capture operation under this mode.
+   * @return {!Promise}
+   * @protected
+   * @abstract
+   */
+  async start_() {}
+
+  /**
+   * Stops the ongoing capture operation under this mode.
+   * @protected
+   */
+  stop_() {}
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/photo.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/photo.js
new file mode 100644
index 0000000..9a0f298
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/photo.js
@@ -0,0 +1,224 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {Filenamer} from '../../../models/file_namer.js';
+import * as filesystem from '../../../models/file_system.js';
+import {DeviceOperator, parseMetadata} from '../../../mojo/device_operator.js';
+import {CrosImageCapture} from '../../../mojo/image_capture.js';
+import {PerfEvent} from '../../../perf.js';
+import * as state from '../../../state.js';
+import * as toast from '../../../toast.js';
+import {
+  Facing,  // eslint-disable-line no-unused-vars
+  Resolution,
+} from '../../../type.js';
+import * as util from '../../../util.js';
+
+import {ModeBase} from './mode_base.js';
+
+/**
+ * Contains photo taking result.
+ * @typedef {{
+ *     resolution: !Resolution,
+ *     blob: !Blob,
+ *     isVideoSnapshot: (boolean|undefined),
+ * }}
+ */
+export let PhotoResult;
+
+/**
+ * Provides external dependency functions used by photo mode and handles the
+ * captured result photo.
+ * @interface
+ */
+export class PhotoHandler {
+  /**
+   * Handles the result photo.
+   * @param {!PhotoResult} photo Captured photo result.
+   * @param {string} name Name of the photo result to be saved as.
+   * @return {!Promise}
+   * @abstract
+   */
+  handleResultPhoto(photo, name) {}
+
+  /**
+   * Plays UI effect when taking photo.
+   */
+  playShutterEffect() {}
+}
+
+
+/**
+ * Photo mode capture controller.
+ */
+export class Photo extends ModeBase {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {?Resolution} captureResolution
+   * @param {!PhotoHandler} handler
+   */
+  constructor(stream, facing, captureResolution, handler) {
+    super(stream, facing, captureResolution);
+
+    /**
+     * @const {!PhotoHandler}
+     * @protected
+     */
+    this.handler_ = handler;
+
+    /**
+     * CrosImageCapture object to capture still photos.
+     * @type {?CrosImageCapture}
+     * @protected
+     */
+    this.crosImageCapture_ = null;
+
+    /**
+     * The observer id for saving metadata.
+     * @type {?number}
+     * @protected
+     */
+    this.metadataObserverId_ = null;
+
+    /**
+     * Metadata names ready to be saved.
+     * @type {!Array<string>}
+     * @protected
+     */
+    this.metadataNames_ = [];
+  }
+
+  /**
+   * @override
+   */
+  async start_() {
+    if (this.crosImageCapture_ === null) {
+      this.crosImageCapture_ =
+          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 image = await util.blobToImage(blob);
+      const resolution = new Resolution(image.width, image.height);
+      await this.handler_.handleResultPhoto({resolution, blob}, imageName);
+      state.set(
+          PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false,
+          {resolution, facing: this.facing_});
+    } catch (e) {
+      state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {hasError: true});
+      state.set(
+          PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {hasError: true});
+      toast.show('error_msg_take_photo_failed');
+      throw e;
+    }
+  }
+
+  /**
+   * Adds an observer to save metadata.
+   * @return {!Promise} Promise for the operation.
+   */
+  async addMetadataObserver() {
+    if (!this.stream_) {
+      return;
+    }
+
+    const deviceOperator = await DeviceOperator.getInstance();
+    if (!deviceOperator) {
+      return;
+    }
+
+    const cameraMetadataTagInverseLookup = {};
+    Object.entries(cros.mojom.CameraMetadataTag).forEach(([key, value]) => {
+      if (key === 'MIN_VALUE' || key === 'MAX_VALUE') {
+        return;
+      }
+      cameraMetadataTagInverseLookup[value] = key;
+    });
+
+    const callback = (metadata) => {
+      const parsedMetadata = {};
+      for (const entry of metadata.entries) {
+        const key = cameraMetadataTagInverseLookup[entry.tag];
+        if (key === undefined) {
+          // TODO(kaihsien): Add support for vendor tags.
+          continue;
+        }
+
+        const val = parseMetadata(entry);
+        parsedMetadata[key] = val;
+      }
+
+      filesystem.saveBlob(
+          new Blob(
+              [JSON.stringify(parsedMetadata, null, 2)],
+              {type: 'application/json'}),
+          this.metadataNames_.shift());
+    };
+
+    const deviceId = this.stream_.getVideoTracks()[0].getSettings().deviceId;
+    this.metadataObserverId_ = await deviceOperator.addMetadataObserver(
+        deviceId, callback, cros.mojom.StreamType.JPEG_OUTPUT);
+  }
+
+  /**
+   * Removes the observer that saves metadata.
+   * @return {!Promise} Promise for the operation.
+   */
+  async removeMetadataObserver() {
+    if (!this.stream_ || this.metadataObserverId_ === null) {
+      return;
+    }
+
+    const deviceOperator = await DeviceOperator.getInstance();
+    if (!deviceOperator) {
+      return;
+    }
+
+    const deviceId = this.stream_.getVideoTracks()[0].getSettings().deviceId;
+    const isSuccess = await deviceOperator.removeMetadataObserver(
+        deviceId, this.metadataObserverId_);
+    if (!isSuccess) {
+      console.error(`Failed to remove metadata observer with id: ${
+          this.metadataObserverId_}`);
+    }
+    this.metadataObserverId_ = null;
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/portrait.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/portrait.js
new file mode 100644
index 0000000..b115884
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/portrait.js
@@ -0,0 +1,119 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {Filenamer} from '../../../models/file_namer.js';
+import {CrosImageCapture} from '../../../mojo/image_capture.js';
+import {PerfEvent} from '../../../perf.js';
+import * as state from '../../../state.js';
+import * as toast from '../../../toast.js';
+import {
+  Facing,      // eslint-disable-line no-unused-vars
+  Resolution,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+import * as util from '../../../util.js';
+
+import {
+  Photo,
+  PhotoHandler,  // eslint-disable-line no-unused-vars
+} from './photo.js';
+
+/**
+ * Portrait mode capture controller.
+ */
+export class Portrait extends Photo {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {?Resolution} captureResolution
+   * @param {!PhotoHandler} handler
+   */
+  constructor(stream, facing, captureResolution, handler) {
+    super(stream, facing, captureResolution, handler);
+  }
+
+  /**
+   * @override
+   */
+  async start_() {
+    if (this.crosImageCapture_ === null) {
+      this.crosImageCapture_ =
+          new CrosImageCapture(this.stream_.getVideoTracks()[0]);
+    }
+
+    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 filenamer = new Filenamer();
+    const refImageName = filenamer.newBurstName(false);
+    const portraitImageName = filenamer.newBurstName(true);
+
+    if (this.metadataObserverId_ !== null) {
+      [refImageName, portraitImageName].forEach((/** string */ imageName) => {
+        this.metadataNames_.push(Filenamer.getMetadataName(imageName));
+      });
+    }
+
+    let /** ?Promise<!Blob> */ reference;
+    let /** ?Promise<!Blob> */ portrait;
+
+    try {
+      [reference, portrait] = await this.crosImageCapture_.takePhoto(
+          photoSettings, [cros.mojom.Effect.PORTRAIT_MODE]);
+      this.handler_.playShutterEffect();
+    } catch (e) {
+      toast.show('error_msg_take_photo_failed');
+      throw e;
+    }
+
+    state.set(PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, true);
+    let hasError = false;
+
+    /**
+     * @param {!Promise<!Blob>} p
+     * @param {string} imageName
+     * @return {!Promise}
+     */
+    const saveResult = async (p, imageName) => {
+      const isPortrait = Object.is(p, portrait);
+      let /** ?Blob */ blob = null;
+      try {
+        blob = await p;
+      } catch (e) {
+        hasError = true;
+        toast.show(
+            isPortrait ? 'error_msg_take_portrait_photo_failed' :
+                         'error_msg_take_photo_failed');
+        throw e;
+      }
+      const {width, height} = await util.blobToImage(blob);
+      await this.handler_.handleResultPhoto(
+          {resolution: new Resolution(width, height), blob}, imageName);
+    };
+
+    const refSave = saveResult(reference, refImageName);
+    const portraitSave = saveResult(portrait, portraitImageName);
+    try {
+      await portraitSave;
+    } catch (e) {
+      hasError = true;
+      // Portrait image may failed due to absence of human faces.
+      // TODO(inker): Log non-intended error.
+    }
+    await refSave;
+    state.set(
+        PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false,
+        {hasError, facing: this.facing_});
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/recordtime.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/record_time.js
similarity index 97%
rename from chromeos/components/camera_app_ui/resources/src/js/views/camera/recordtime.js
rename to chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/record_time.js
index 810bc2d1..c560975 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera/recordtime.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/record_time.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import {speak} from '../../toast.js';
+import {speak} from '../../../toast.js';
 
 /**
  * Controller for the record-time of Camera view.
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/square.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/square.js
new file mode 100644
index 0000000..8a34666e
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/square.js
@@ -0,0 +1,87 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {
+  Facing,      // eslint-disable-line no-unused-vars
+  Resolution,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+import * as util from '../../../util.js';
+
+import {
+  Photo,
+  PhotoHandler,  // eslint-disable-line no-unused-vars
+} from './photo.js';
+
+/**
+ * Crops out maximum possible centered square from the image blob.
+ * @param {!Blob} blob
+ * @return {!Promise<!Blob>} Promise with result cropped square image.
+ */
+async function cropSquare(blob) {
+  const img = await util.blobToImage(blob);
+  const side = Math.min(img.width, img.height);
+  const canvas = document.createElement('canvas');
+  canvas.width = side;
+  canvas.height = side;
+  const ctx = canvas.getContext('2d');
+  ctx.drawImage(
+      img, Math.floor((img.width - side) / 2),
+      Math.floor((img.height - side) / 2), side, side, 0, 0, side, side);
+  const croppedBlob = await new Promise((resolve) => {
+    canvas.toBlob(resolve, 'image/jpeg');
+  });
+  croppedBlob.resolution = blob.resolution;
+  return croppedBlob;
+}
+
+/**
+ * Cuts the returned photo into square and passed to underlying PhotoHandler.
+ * @implements {PhotoHandler}
+ */
+class SquarePhotoHandler {
+  /**
+   * @param {!PhotoHandler} handler
+   */
+  constructor(handler) {
+    /**
+     * @const {!PhotoHandler}
+     */
+    this.handler_ = handler;
+  }
+
+  /**
+   * @override
+   */
+  async handleResultPhoto(result, ...args) {
+    // Since the image blob after square cut will lose its EXIF including
+    // orientation information. Corrects the orientation before the square
+    // cut.
+    result.blob = await new Promise(
+        (resolve, reject) => util.orientPhoto(result.blob, resolve, reject));
+    result.blob = await cropSquare(result.blob);
+    await this.handler_.handleResultPhoto(result, ...args);
+  }
+
+  /**
+   * @override
+   */
+  playShutterEffect() {
+    this.handler_.playShutterEffect();
+  }
+}
+
+/**
+ * Square mode capture controller.
+ */
+export class Square extends Photo {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {?Resolution} captureResolution
+   * @param {!PhotoHandler} handler
+   */
+  constructor(stream, facing, captureResolution, handler) {
+    super(stream, facing, captureResolution, new SquarePhotoHandler(handler));
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/video.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/video.js
new file mode 100644
index 0000000..9073b8c8
--- /dev/null
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/mode/video.js
@@ -0,0 +1,361 @@
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {AsyncJobQueue} from '../../../async_job_queue.js';
+import {browserProxy} from '../../../browser_proxy/browser_proxy.js';
+import {assert} from '../../../chrome_util.js';
+import {Filenamer} from '../../../models/file_namer.js';
+import {
+  VideoSaver,  // eslint-disable-line no-unused-vars
+} from '../../../models/video_saver.js';
+import {PerfEvent} from '../../../perf.js';
+import * as sound from '../../../sound.js';
+import * as state from '../../../state.js';
+import * as toast from '../../../toast.js';
+import {
+  Facing,  // eslint-disable-line no-unused-vars
+  Resolution,
+  ResolutionList,  // eslint-disable-line no-unused-vars
+} from '../../../type.js';
+import * as util from '../../../util.js';
+import {WaitableEvent} from '../../../waitable_event.js';
+
+import {ModeBase} from './mode_base.js';
+import {PhotoResult} from './photo.js';  // eslint-disable-line no-unused-vars
+import {RecordTime} from './record_time.js';
+
+/**
+ * Video recording MIME type. Mkv with AVC1 is the only preferred format.
+ * @type {string}
+ */
+const VIDEO_MIMETYPE = browserProxy.isMp4RecordingEnabled() ?
+    'video/x-matroska;codecs=avc1,pcm' :
+    'video/x-matroska;codecs=avc1';
+
+/**
+ * Contains video recording result.
+ */
+export class VideoResult {
+  /**
+   * @param {{
+   *     resolution: !Resolution,
+   *     duration: (number|undefined),
+   *     videoSaver: !VideoSaver,
+   *     everPaused: boolean,
+   * }} params
+   */
+  constructor({resolution, duration = 0, videoSaver, everPaused}) {
+    /**
+     * @const {!Resolution}
+     * @public
+     */
+    this.resolution = resolution;
+
+    /**
+     * @const {number}
+     * @public
+     */
+    this.duration = duration || 0;
+
+    /**
+     * @const {!VideoSaver}
+     * @public
+     */
+    this.videoSaver = videoSaver;
+
+    /**
+     * @const {boolean}
+     * @public
+     */
+    this.everPaused = everPaused;
+  }
+}
+
+/**
+ * Provides functions with external dependency used by video mode and handles
+ * the captured result video.
+ * @interface
+ */
+export class VideoHandler {
+  /**
+   * Creates VideoSaver to save video capture result.
+   * @return {!Promise<!VideoSaver>}
+   * @abstract
+   */
+  createVideoSaver() {}
+
+  /**
+   * Handles the result video.
+   * @param {!VideoResult} video Captured video result.
+   * @return {!Promise}
+   * @abstract
+   */
+  handleResultVideo(video) {}
+
+  /**
+   * Handles the result video snapshot.
+   * @param {!PhotoResult} photo photo Captured video snapshot photo.
+   * @param {string} name Name of the video snapshot result to be saved as.
+   * @return {!Promise}
+   * @abstract
+   */
+  handleResultPhoto(photo, name) {}
+
+  /**
+   * Plays UI effect when doing video snapshot.
+   */
+  playShutterEffect() {}
+
+  /**
+   * Gets frame image blob from current preview.
+   * @return {!Promise<!Blob>}
+   * @abstract
+   */
+  getPreviewFrame() {}
+}
+
+/**
+ * Video mode capture controller.
+ */
+export class Video extends ModeBase {
+  /**
+   * @param {!MediaStream} stream
+   * @param {!Facing} facing
+   * @param {!VideoHandler} handler
+   */
+  constructor(stream, facing, handler) {
+    super(stream, facing, null);
+
+    /**
+     * @const {!VideoHandler}
+     * @private
+     */
+    this.handler_ = handler;
+
+    /**
+     * Promise for play start sound delay.
+     * @type {?Promise}
+     * @private
+     */
+    this.startSound_ = null;
+
+    /**
+     * MediaRecorder object to record motion pictures.
+     * @type {?MediaRecorder}
+     * @private
+     */
+    this.mediaRecorder_ = null;
+
+    /**
+     * Record-time for the elapsed recording time.
+     * @type {!RecordTime}
+     * @private
+     */
+    this.recordTime_ = new RecordTime();
+
+    /**
+     * Queueing all taking video snapshot jobs requested in a single recording.
+     * @type {!AsyncJobQueue}
+     * @private
+     */
+    this.snapshots_ = new AsyncJobQueue();
+
+    /**
+     * Promise for process of toggling video pause/resume. Sets to null if CCA
+     * is already paused or resumed.
+     * @type {?Promise}
+     * @private
+     */
+    this.togglePaused_ = null;
+
+    /**
+     * Whether current recording ever paused/resumed before it ended.
+     */
+    this.everPaused_ = false;
+  }
+
+  /**
+   * Takes a video snapshot during recording.
+   * @return {!Promise} Promise resolved when video snapshot is finished.
+   */
+  takeSnapshot() {
+    const doSnapshot = async () => {
+      const blob = await this.handler_.getPreviewFrame();
+      this.handler_.playShutterEffect();
+      const {width, height} = await util.blobToImage(blob);
+      const imageName = (new Filenamer()).newImageName();
+      await this.handler_.handleResultPhoto(
+          {
+            resolution: new Resolution(width, height),
+            blob,
+            isVideoSnapshot: true,
+          },
+          imageName);
+    };
+    this.snapshots_.push(doSnapshot);
+    return this.snapshots_.flush();
+  }
+
+  /**
+   * Toggles pause/resume state of video recording.
+   * @return {!Promise} Promise resolved when recording is paused/resumed.
+   */
+  async togglePaused() {
+    if (!state.get(state.State.RECORDING)) {
+      return;
+    }
+    if (this.togglePaused_ !== null) {
+      return this.togglePaused_;
+    }
+    this.everPaused_ = true;
+    const waitable = new WaitableEvent();
+    this.togglePaused_ = waitable.wait();
+
+    assert(this.mediaRecorder_.state !== 'inactive');
+    const toBePaused = this.mediaRecorder_.state !== 'paused';
+    const toggledEvent = toBePaused ? 'pause' : 'resume';
+    const onToggled = () => {
+      this.mediaRecorder_.removeEventListener(toggledEvent, onToggled);
+      state.set(state.State.RECORDING_PAUSED, toBePaused);
+      this.togglePaused_ = null;
+      waitable.signal();
+    };
+    const playEffect = async () => {
+      state.set(state.State.RECORDING_UI_PAUSED, toBePaused);
+      await sound.play(toBePaused ? '#sound-rec-pause' : '#sound-rec-start');
+    };
+
+    this.mediaRecorder_.addEventListener(toggledEvent, onToggled);
+    if (toBePaused) {
+      waitable.wait().then(playEffect);
+      this.recordTime_.stop({pause: true});
+      this.mediaRecorder_.pause();
+    } else {
+      await playEffect();
+      this.recordTime_.start({resume: true});
+      this.mediaRecorder_.resume();
+    }
+
+    return waitable.wait();
+  }
+
+  /**
+   * @override
+   */
+  async start_() {
+    this.snapshots_ = new AsyncJobQueue();
+    this.togglePaused_ = null;
+    this.startSound_ = sound.play('#sound-rec-start');
+    this.everPaused_ = false;
+    try {
+      await this.startSound_;
+    } finally {
+      this.startSound_ = null;
+    }
+
+    if (this.mediaRecorder_ === null) {
+      try {
+        if (!MediaRecorder.isTypeSupported(VIDEO_MIMETYPE)) {
+          throw new Error('The preferred mimeType is not supported.');
+        }
+        this.mediaRecorder_ =
+            new MediaRecorder(this.stream_, {mimeType: VIDEO_MIMETYPE});
+      } catch (e) {
+        toast.show('error_msg_record_start_failed');
+        throw e;
+      }
+    }
+
+    this.recordTime_.start({resume: false});
+    let /** ?VideoSaver */ videoSaver = null;
+    let /** number */ duration = 0;
+    try {
+      videoSaver = await this.captureVideo_();
+    } catch (e) {
+      toast.show('error_msg_empty_recording');
+      throw e;
+    } finally {
+      duration = this.recordTime_.stop({pause: false});
+    }
+    sound.play('#sound-rec-end');
+
+    const settings = this.stream_.getVideoTracks()[0].getSettings();
+    const resolution = new Resolution(settings.width, settings.height);
+    state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, true);
+    try {
+      await this.handler_.handleResultVideo(new VideoResult(
+          {resolution, duration, videoSaver, everPaused: this.everPaused_}));
+      state.set(
+          PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false,
+          {resolution, facing: this.facing_});
+    } catch (e) {
+      state.set(
+          PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {hasError: true});
+      throw e;
+    }
+
+    await this.snapshots_.flush();
+  }
+
+  /**
+   * @override
+   */
+  stop_() {
+    if (this.startSound_ && this.startSound_.cancel) {
+      this.startSound_.cancel();
+    }
+    if (this.mediaRecorder_ &&
+        (this.mediaRecorder_.state === 'recording' ||
+         this.mediaRecorder_.state === 'paused')) {
+      this.mediaRecorder_.stop();
+    }
+  }
+
+  /**
+   * Starts recording and waits for stop recording event triggered by stop
+   * shutter.
+   * @return {!Promise<!VideoSaver>} Saves recorded video.
+   * @private
+   */
+  async captureVideo_() {
+    const saver = await this.handler_.createVideoSaver();
+
+    return new Promise((resolve, reject) => {
+      let noChunk = true;
+
+      const ondataavailable = (event) => {
+        if (event.data && event.data.size > 0) {
+          noChunk = false;
+          saver.write(event.data);
+        }
+      };
+      const onstop = (event) => {
+        state.set(state.State.RECORDING, false);
+        state.set(state.State.RECORDING_PAUSED, false);
+        state.set(state.State.RECORDING_UI_PAUSED, false);
+
+        this.mediaRecorder_.removeEventListener(
+            'dataavailable', ondataavailable);
+        this.mediaRecorder_.removeEventListener('stop', onstop);
+
+        if (noChunk) {
+          reject(new Error('Video blob error.'));
+        } else {
+          // TODO(yuli): Handle insufficient storage.
+          resolve(saver);
+        }
+      };
+      const onstart = () => {
+        state.set(state.State.RECORDING, true);
+        this.mediaRecorder_.removeEventListener('start', onstart);
+      };
+      this.mediaRecorder_.addEventListener('dataavailable', ondataavailable);
+      this.mediaRecorder_.addEventListener('stop', onstop);
+      this.mediaRecorder_.addEventListener('start', onstart);
+      this.mediaRecorder_.start(100);
+      state.set(state.State.RECORDING_PAUSED, false);
+      state.set(state.State.RECORDING_UI_PAUSED, false);
+    });
+  }
+}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/modes.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/modes.js
deleted file mode 100644
index 9e583de..0000000
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera/modes.js
+++ /dev/null
@@ -1,1219 +0,0 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import {AsyncJobQueue} from '../../async_job_queue.js';
-import {browserProxy} from '../../browser_proxy/browser_proxy.js';
-import {assert, assertInstanceof} from '../../chrome_util.js';
-import {
-  CaptureCandidate,           // eslint-disable-line no-unused-vars
-  ConstraintsPreferrer,       // eslint-disable-line no-unused-vars
-  PhotoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
-  VideoConstraintsPreferrer,  // eslint-disable-line no-unused-vars
-} from '../../device/constraints_preferrer.js';
-import {Filenamer} from '../../models/file_namer.js';
-import * as filesystem from '../../models/file_system.js';
-// eslint-disable-next-line no-unused-vars
-import {VideoSaver} from '../../models/video_saver.js';
-import {DeviceOperator, parseMetadata} from '../../mojo/device_operator.js';
-import {CrosImageCapture} from '../../mojo/image_capture.js';
-import {PerfEvent} from '../../perf.js';
-import * as sound from '../../sound.js';
-import * as state from '../../state.js';
-import * as toast from '../../toast.js';
-import {
-  Facing,
-  Mode,
-  Resolution,
-  ResolutionList,  // eslint-disable-line no-unused-vars
-} from '../../type.js';
-import * as util from '../../util.js';
-import {WaitableEvent} from '../../waitable_event.js';
-
-import {RecordTime} from './recordtime.js';
-
-/**
- * Contains video recording result.
- * @typedef {{
- *   resolution: !Resolution,
- *   duration: number,
- *   videoSaver: !VideoSaver,
- *   everPaused: boolean,
- * }}
- */
-export let VideoResult;
-
-/**
- * Contains photo taking result.
- * @typedef {{
- *   resolution: !Resolution,
- *   blob: !Blob,
- *   isVideoSnapshot: (boolean|undefined),
- * }}
- */
-export let PhotoResult;
-
-/**
- * Callback to trigger mode switching.
- * return {!Promise}
- * @typedef {function(): !Promise}
- */
-export let DoSwitchMode;
-
-/**
- * Callback for saving photo capture result.
- * param {!PhotoResult} Captured photo result.
- * param {string} Name of the photo result to be saved as.
- * return {!Promise}
- * @typedef {function(!PhotoResult, string): !Promise}
- */
-export let DoSavePhoto;
-
-/**
- * Callback for allocating VideoSaver to save video capture result.
- * @typedef {function(): !Promise<!VideoSaver>}
- */
-export let CreateVideoSaver;
-
-/**
- * Callback for saving video capture result.
- * param {!VideoResult} Captured video result.
- * return {!Promise}
- * @typedef {function(!VideoResult): !Promise}
- */
-export let DoSaveVideo;
-
-/**
- * Callback for playing shutter effect.
- * @typedef {function()}
- */
-export let PlayShutterEffect;
-
-/**
- * Callback for getting frame image blob from current preview.
- * @typedef {function(): !Promise<!Blob>}
- */
-export let GetPreviewFrame;
-
-/* eslint-disable no-unused-vars */
-
-/**
- * The abstract interface for the mode configuration.
- * @interface
- */
-class ModeConfig {
-  /**
-   * Factory function to create capture object for this mode.
-   * @return {!ModeBase}
-   * @abstract
-   */
-  captureFactory() {}
-
-  /**
-   * @param {?string} deviceId
-   * @return {!Promise<boolean>} Resolves to boolean indicating whether the mode
-   *     is supported by video device with specified device id.
-   * @abstract
-   */
-  async isSupported(deviceId) {}
-
-  /**
-   * Get stream constraints for HALv1 of this mode.
-   * @param {?string} deviceId
-   * @return {!Array<!MediaStreamConstraints>}
-   * @abstract
-   */
-  getV1Constraints(deviceId) {}
-
-  /* eslint-disable getter-return */
-
-  /**
-   * HALv3 constraints preferrer for this mode.
-   * @return {!ConstraintsPreferrer}
-   * @abstract
-   */
-  get constraintsPreferrer() {}
-
-  /**
-   * Mode to be fallbacked to when fail to configure this mode.
-   * @return {!Mode}
-   * @abstract
-   */
-  get nextMode() {}
-
-  /**
-   * Capture intent of this mode.
-   * @return {!cros.mojom.CaptureIntent}
-   * @abstract
-   */
-  get captureIntent() {}
-
-  /* eslint-enable getter-return */
-}
-
-/* eslint-enable no-unused-vars */
-
-/**
- * Mode controller managing capture sequence of different camera mode.
- */
-export class Modes {
-  /**
-   * @param {!Mode} defaultMode Default mode to be switched to.
-   * @param {!PhotoConstraintsPreferrer} photoPreferrer
-   * @param {!VideoConstraintsPreferrer} videoPreferrer
-   * @param {!DoSwitchMode} doSwitchMode
-   * @param {!DoSavePhoto} doSavePhoto
-   * @param {!CreateVideoSaver} createVideoSaver
-   * @param {!DoSaveVideo} doSaveVideo
-   * @param {!PlayShutterEffect} playShutterEffect
-   * @param {!GetPreviewFrame} getPreviewFrame
-   */
-  constructor(
-      defaultMode, photoPreferrer, videoPreferrer, doSwitchMode, doSavePhoto,
-      createVideoSaver, doSaveVideo, playShutterEffect, getPreviewFrame) {
-    /**
-     * @type {!DoSwitchMode}
-     * @private
-     */
-    this.doSwitchMode_ = doSwitchMode;
-
-    /**
-     * Capture controller of current camera mode.
-     * @type {?ModeBase}
-     */
-    this.current = null;
-
-    /**
-     * Stream of current mode.
-     * @type {?MediaStream}
-     * @private
-     */
-    this.stream_ = null;
-
-    /**
-     * Camera facing of current mode.
-     * @type {!Facing}
-     * @private
-     */
-    this.facing_ = Facing.UNKNOWN;
-
-    /**
-     * @type {!HTMLElement}
-     * @private
-     */
-    this.modesGroup_ =
-        assertInstanceof(document.querySelector('#modes-group'), HTMLElement);
-
-    /**
-     * @type {?Resolution}
-     * @private
-     */
-    this.captureResolution_ = null;
-
-    /**
-     * Returns a set of available constraints for HALv1 device.
-     * @param {boolean} videoMode Is getting constraints for video mode.
-     * @param {?string} deviceId Id of video device.
-     * @return {!Array<!MediaStreamConstraints>} Result of
-     *     constraints-candidates.
-     */
-    const getV1Constraints = function(videoMode, deviceId) {
-      const /** !Array<!MediaTrackConstraints> */ baseConstraints = [
-        {
-          aspectRatio: {ideal: videoMode ? 1.7777777778 : 1.3333333333},
-          width: {min: 1280},
-          frameRate: {min: 20, ideal: 30},
-        },
-        {
-          width: {min: 640},
-          frameRate: {min: 20, ideal: 30},
-        },
-      ];
-      return baseConstraints.map((constraint) => {
-        if (deviceId) {
-          constraint.deviceId = {exact: deviceId};
-        } else {
-          // HALv1 devices are unable to know facing before stream
-          // configuration, deviceId is set to null for requesting camera with
-          // default facing.
-          constraint.facingMode = {exact: util.getDefaultFacing()};
-        }
-        return {
-          audio: videoMode ? {echoCancellation: false} : false,
-          video: constraint,
-        };
-      });
-    };
-
-    /**
-     * Mode classname and related functions and attributes.
-     * @type {!Object<!Mode, !ModeConfig>}
-     * @private
-     */
-    this.allModes_ = {
-      [Mode.VIDEO]: {
-        captureFactory: () => new Video(
-            assertInstanceof(this.stream_, MediaStream), this.facing_,
-            createVideoSaver, doSaveVideo, doSavePhoto, getPreviewFrame,
-            playShutterEffect),
-        isSupported: async () => true,
-        constraintsPreferrer: videoPreferrer,
-        getV1Constraints: getV1Constraints.bind(this, true),
-        nextMode: Mode.PHOTO,
-        captureIntent: cros.mojom.CaptureIntent.VIDEO_RECORD,
-      },
-      [Mode.PHOTO]: {
-        captureFactory: () => new Photo(
-            assertInstanceof(this.stream_, MediaStream), this.facing_,
-            doSavePhoto, this.captureResolution_, playShutterEffect),
-        isSupported: async () => true,
-        constraintsPreferrer: photoPreferrer,
-        getV1Constraints: getV1Constraints.bind(this, false),
-        nextMode: Mode.SQUARE,
-        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
-      },
-      [Mode.SQUARE]: {
-        captureFactory: () => new Square(
-            assertInstanceof(this.stream_, MediaStream), this.facing_,
-            doSavePhoto, this.captureResolution_, playShutterEffect),
-        isSupported: async () => true,
-        constraintsPreferrer: photoPreferrer,
-        getV1Constraints: getV1Constraints.bind(this, false),
-        nextMode: Mode.PHOTO,
-        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
-      },
-      [Mode.PORTRAIT]: {
-        captureFactory: () => new Portrait(
-            assertInstanceof(this.stream_, MediaStream), this.facing_,
-            doSavePhoto, this.captureResolution_, playShutterEffect),
-        isSupported: async (deviceId) => {
-          if (deviceId === null) {
-            return false;
-          }
-          const deviceOperator = await DeviceOperator.getInstance();
-          if (deviceOperator === null) {
-            return false;
-          }
-          return await deviceOperator.isPortraitModeSupported(deviceId);
-        },
-        constraintsPreferrer: photoPreferrer,
-        getV1Constraints: getV1Constraints.bind(this, false),
-        nextMode: Mode.PHOTO,
-        captureIntent: cros.mojom.CaptureIntent.STILL_CAPTURE,
-      },
-    };
-
-    document.querySelectorAll('.mode-item>input').forEach((element) => {
-      element.addEventListener('click', (event) => {
-        if (!state.get(state.State.STREAMING) ||
-            state.get(state.State.TAKING)) {
-          event.preventDefault();
-        }
-      });
-      element.addEventListener('change', async (event) => {
-        if (element.checked) {
-          const mode = element.dataset.mode;
-          this.updateModeUI_(mode);
-          state.set(state.State.MODE_SWITCHING, true);
-          const isSuccess = await this.doSwitchMode_();
-          state.set(state.State.MODE_SWITCHING, false, {hasError: !isSuccess});
-        }
-      });
-    });
-
-    [state.State.EXPERT, state.State.SAVE_METADATA].forEach(
-        (/** !state.State */ s) => {
-          state.addObserver(s, this.updateSaveMetadata_.bind(this));
-        });
-
-    // Set default mode when app started.
-    this.updateModeUI_(defaultMode);
-  }
-
-  /**
-   * @return {!Array<!Mode>}
-   * @private
-   */
-  get allModeNames_() {
-    return Object.keys(this.allModes_);
-  }
-
-  /**
-   * Updates state of mode related UI to the target mode.
-   * @param {!Mode} mode Mode to be toggled.
-   * @private
-   */
-  updateModeUI_(mode) {
-    this.allModeNames_.forEach((m) => state.set(m, m === mode));
-    const element =
-        document.querySelector(`.mode-item>input[data-mode=${mode}]`);
-    element.checked = true;
-    const wrapper = element.parentElement;
-    let scrollTop = wrapper.offsetTop - this.modesGroup_.offsetHeight / 2 +
-        wrapper.offsetHeight / 2;
-    // Make photo mode scroll slightly upper so that the third mode item falls
-    // in blur area: crbug.com/988869
-    if (mode === Mode.PHOTO) {
-      scrollTop -= 16;
-    }
-    this.modesGroup_.scrollTo({
-      left: 0,
-      top: scrollTop,
-      behavior: 'smooth',
-    });
-  }
-
-  /**
-   * Gets all mode candidates. Desired trying sequence of candidate modes is
-   * reflected in the order of the returned array.
-   * @return {!Array<!Mode>} Mode candidates to be tried out.
-   */
-  getModeCandidates() {
-    const tried = {};
-    const /** !Array<!Mode> */ results = [];
-    let mode = this.allModeNames_.find(state.get);
-    assert(mode !== undefined);
-    while (!tried[mode]) {
-      tried[mode] = true;
-      results.push(mode);
-      mode = this.allModes_[mode].nextMode;
-    }
-    return results;
-  }
-
-  /**
-   * Gets all available capture resolution and its corresponding preview
-   * constraints for the given mode.
-   * @param {!Mode} mode
-   * @param {string} deviceId
-   * @return {!Array<!CaptureCandidate>}
-   */
-  getResolutionCandidates(mode, deviceId) {
-    return this.allModes_[mode].constraintsPreferrer.getSortedCandidates(
-        deviceId);
-  }
-
-  /**
-   * Gets capture resolution and its corresponding preview constraints for the
-   * given mode on camera HALv1 device.
-   * @param {!Mode} mode
-   * @param {?string} deviceId
-   * @return {!Array<!CaptureCandidate>}
-   */
-  getResolutionCandidatesV1(mode, deviceId) {
-    const previewCandidates = this.allModes_[mode].getV1Constraints(deviceId);
-    return [{resolution: null, previewCandidates}];
-  }
-
-  /**
-   * Gets capture intent for the given mode.
-   * @param {!Mode} mode
-   * @return {!cros.mojom.CaptureIntent} Capture intent for the given mode.
-   */
-  getCaptureIntent(mode) {
-    return this.allModes_[mode].captureIntent;
-  }
-
-  /**
-   * Gets supported modes for video device of given device id.
-   * @param {?string} deviceId Device id of the video device.
-   * @return {!Promise<!Array<!Mode>>} All supported mode for
-   *     the video device.
-   */
-  async getSupportedModes(deviceId) {
-    const /** !Array<!Mode> */ supportedModes = [];
-    for (const mode of this.allModeNames_) {
-      const obj = this.allModes_[mode];
-      if (await obj.isSupported(deviceId)) {
-        supportedModes.push(mode);
-      }
-    }
-    return supportedModes;
-  }
-
-  /**
-   * Updates mode selection UI according to given device id.
-   * @param {?string} deviceId
-   * @return {!Promise}
-   */
-  async updateModeSelectionUI(deviceId) {
-    const supportedModes = await this.getSupportedModes(deviceId);
-    document.querySelectorAll('.mode-item').forEach((element) => {
-      const radio = element.querySelector('input[type=radio]');
-      element.classList.toggle(
-          'hide', !supportedModes.includes(radio.dataset.mode));
-    });
-    this.modesGroup_.classList.toggle('scrollable', supportedModes.length > 3);
-    this.modesGroup_.classList.remove('hide');
-  }
-
-  /**
-   * Creates and updates new current mode object.
-   * @param {!Mode} mode Classname of mode to be updated.
-   * @param {!MediaStream} stream Stream of the new switching mode.
-   * @param {!Facing} facing Camera facing of the current mode.
-   * @param {?string} deviceId Device id of currently working video device.
-   * @param {?Resolution} captureResolution Capturing resolution width and
-   *     height.
-   * @return {!Promise}
-   */
-  async updateMode(mode, stream, facing, deviceId, captureResolution) {
-    if (this.current !== null) {
-      await this.current.stopCapture();
-    }
-    this.updateModeUI_(mode);
-    this.stream_ = stream;
-    this.facing_ = facing;
-    this.captureResolution_ = captureResolution;
-    this.current = this.allModes_[mode].captureFactory();
-    if (deviceId && this.captureResolution_) {
-      this.allModes_[mode].constraintsPreferrer.updateValues(
-          deviceId, stream, facing, this.captureResolution_);
-    }
-    await this.updateSaveMetadata_();
-  }
-
-  /**
-   * Checks whether to save image metadata or not.
-   * @return {!Promise} Promise for the operation.
-   * @private
-   */
-  async updateSaveMetadata_() {
-    if (state.get(state.State.EXPERT) && state.get(state.State.SAVE_METADATA)) {
-      await this.enableSaveMetadata_();
-    } else {
-      await this.disableSaveMetadata_();
-    }
-  }
-
-  /**
-   * Enables save metadata of subsequent photos in the current mode.
-   * @return {!Promise} Promise for the operation.
-   * @private
-   */
-  async enableSaveMetadata_() {
-    if (this.current !== null) {
-      await this.current.addMetadataObserver();
-    }
-  }
-
-  /**
-   * Disables save metadata of subsequent photos in the current mode.
-   * @return {!Promise} Promise for the operation.
-   * @private
-   */
-  async disableSaveMetadata_() {
-    if (this.current !== null) {
-      await this.current.removeMetadataObserver();
-    }
-  }
-}
-
-/**
- * Base class for controlling capture sequence in different camera modes.
- * @abstract
- */
-class ModeBase {
-  /**
-   * @param {!MediaStream} stream
-   * @param {!Facing} facing
-   * @param {?Resolution} captureResolution Capturing resolution width and
-   *     height.
-   */
-  constructor(stream, facing, captureResolution) {
-    /**
-     * Stream of current mode.
-     * @type {!MediaStream}
-     * @protected
-     */
-    this.stream_ = stream;
-
-    /**
-     * Camera facing of current mode.
-     * @type {!Facing}
-     * @protected
-     */
-    this.facing_ = facing;
-
-    /**
-     * Capture resolution. May be null on device not support of setting
-     * resolution.
-     * @type {?Resolution}
-     * @private
-     */
-    this.captureResolution_ = captureResolution;
-
-    /**
-     * Promise for ongoing capture operation.
-     * @type {?Promise}
-     * @private
-     */
-    this.capture_ = null;
-  }
-
-  /**
-   * Initiates video/photo capture operation.
-   * @return {!Promise} Promise for ongoing capture operation.
-   */
-  startCapture() {
-    if (this.capture_ === null) {
-      this.capture_ = this.start_().finally(() => this.capture_ = null);
-    }
-    return this.capture_;
-  }
-
-  /**
-   * Stops the ongoing capture operation.
-   * @return {!Promise} Promise for ongoing capture operation.
-   */
-  async stopCapture() {
-    this.stop_();
-    return await this.capture_;
-  }
-
-  /**
-   * Adds an observer to save image metadata.
-   * @return {!Promise} Promise for the operation.
-   */
-  async addMetadataObserver() {}
-
-  /**
-   * Remove the observer that saves metadata.
-   * @return {!Promise} Promise for the operation.
-   */
-  async removeMetadataObserver() {}
-
-  /**
-   * Initiates video/photo capture operation under this mode.
-   * @return {!Promise}
-   * @protected
-   * @abstract
-   */
-  async start_() {}
-
-  /**
-   * Stops the ongoing capture operation under this mode.
-   * @protected
-   */
-  stop_() {}
-}
-
-/**
- * Video recording MIME type. Mkv with AVC1 is the only preferred format.
- * @type {string}
- */
-const VIDEO_MIMETYPE = browserProxy.isMp4RecordingEnabled() ?
-    'video/x-matroska;codecs=avc1,pcm' :
-    'video/x-matroska;codecs=avc1';
-
-/**
- * Video mode capture controller.
- */
-export class Video extends ModeBase {
-  /**
-   * @param {!MediaStream} stream
-   * @param {!Facing} facing
-   * @param {!CreateVideoSaver} createVideoSaver
-   * @param {!DoSaveVideo} doSaveVideo
-   * @param {!DoSavePhoto} doSaveSnapshot
-   * @param {!GetPreviewFrame} getPreviewFrame
-   * @param {!PlayShutterEffect} playShutterEffect
-   */
-  constructor(
-      stream, facing, createVideoSaver, doSaveVideo, doSaveSnapshot,
-      getPreviewFrame, playShutterEffect) {
-    super(stream, facing, null);
-
-    /**
-     * @type {!CreateVideoSaver}
-     * @private
-     */
-    this.createVideoSaver_ = createVideoSaver;
-
-    /**
-     * @type {!DoSaveVideo}
-     * @private
-     */
-    this.doSaveVideo_ = doSaveVideo;
-
-    /**
-     * @type {!DoSavePhoto}
-     * @private
-     */
-    this.doSaveSnapshot_ = doSaveSnapshot;
-
-    /**
-     * @type {!GetPreviewFrame}
-     * @private
-     */
-    this.getPreviewFrame_ = getPreviewFrame;
-
-    /**
-     * @type {!PlayShutterEffect}
-     * @private
-     */
-    this.playShutterEffect_ = playShutterEffect;
-
-    /**
-     * Promise for play start sound delay.
-     * @type {?Promise}
-     * @private
-     */
-    this.startSound_ = null;
-
-    /**
-     * MediaRecorder object to record motion pictures.
-     * @type {?MediaRecorder}
-     * @private
-     */
-    this.mediaRecorder_ = null;
-
-    /**
-     * Record-time for the elapsed recording time.
-     * @type {!RecordTime}
-     * @private
-     */
-    this.recordTime_ = new RecordTime();
-
-    /**
-     * Queueing all taking video snapshot jobs requested in a single recording.
-     * @type {!AsyncJobQueue}
-     * @private
-     */
-    this.snapshots_ = new AsyncJobQueue();
-
-    /**
-     * Promise for process of toggling video pause/resume. Sets to null if CCA
-     * is already paused or resumed.
-     * @type {?Promise}
-     * @private
-     */
-    this.togglePaused_ = null;
-
-    /**
-     * Whether current recording ever paused/resumed before it ended.
-     */
-    this.everPaused_ = false;
-  }
-
-  /**
-   * Takes a video snapshot during recording.
-   * @return {!Promise} Promise resolved when video snapshot is finished.
-   */
-  takeSnapshot() {
-    const doSnapshot = async () => {
-      const blob = await this.getPreviewFrame_();
-      this.playShutterEffect_();
-      const {width, height} = await util.blobToImage(blob);
-      const imageName = (new Filenamer()).newImageName();
-      await this.doSaveSnapshot_(
-          {
-            resolution: new Resolution(width, height),
-            blob,
-            isVideoSnapshot: true,
-          },
-          imageName);
-    };
-    this.snapshots_.push(doSnapshot);
-    return this.snapshots_.flush();
-  }
-
-  /**
-   * Toggles pause/resume state of video recording.
-   * @return {!Promise} Promise resolved when recording is paused/resumed.
-   */
-  async togglePaused() {
-    if (!state.get(state.State.RECORDING)) {
-      return;
-    }
-    if (this.togglePaused_ !== null) {
-      return this.togglePaused_;
-    }
-    this.everPaused_ = true;
-    const waitable = new WaitableEvent();
-    this.togglePaused_ = waitable.wait();
-
-    assert(this.mediaRecorder_.state !== 'inactive');
-    const toBePaused = this.mediaRecorder_.state !== 'paused';
-    const toggledEvent = toBePaused ? 'pause' : 'resume';
-    const onToggled = () => {
-      this.mediaRecorder_.removeEventListener(toggledEvent, onToggled);
-      state.set(state.State.RECORDING_PAUSED, toBePaused);
-      this.togglePaused_ = null;
-      waitable.signal();
-    };
-    const playEffect = async () => {
-      state.set(state.State.RECORDING_UI_PAUSED, toBePaused);
-      await sound.play(toBePaused ? '#sound-rec-pause' : '#sound-rec-start');
-    };
-
-    this.mediaRecorder_.addEventListener(toggledEvent, onToggled);
-    if (toBePaused) {
-      waitable.wait().then(playEffect);
-      this.recordTime_.stop({pause: true});
-      this.mediaRecorder_.pause();
-    } else {
-      await playEffect();
-      this.recordTime_.start({resume: true});
-      this.mediaRecorder_.resume();
-    }
-
-    return waitable.wait();
-  }
-
-  /**
-   * @override
-   */
-  async start_() {
-    this.snapshots_ = new AsyncJobQueue();
-    this.togglePaused_ = null;
-    this.startSound_ = sound.play('#sound-rec-start');
-    this.everPaused_ = false;
-    try {
-      await this.startSound_;
-    } finally {
-      this.startSound_ = null;
-    }
-
-    if (this.mediaRecorder_ === null) {
-      try {
-        if (!MediaRecorder.isTypeSupported(VIDEO_MIMETYPE)) {
-          throw new Error('The preferred mimeType is not supported.');
-        }
-        this.mediaRecorder_ =
-            new MediaRecorder(this.stream_, {mimeType: VIDEO_MIMETYPE});
-      } catch (e) {
-        toast.show('error_msg_record_start_failed');
-        throw e;
-      }
-    }
-
-    this.recordTime_.start({resume: false});
-    let /** ?VideoSaver */ videoSaver = null;
-    let /** number */ duration = 0;
-    try {
-      videoSaver = await this.captureVideo_();
-    } catch (e) {
-      toast.show('error_msg_empty_recording');
-      throw e;
-    } finally {
-      duration = this.recordTime_.stop({pause: false});
-    }
-    sound.play('#sound-rec-end');
-
-    const settings = this.stream_.getVideoTracks()[0].getSettings();
-    const resolution = new Resolution(settings.width, settings.height);
-    state.set(PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, true);
-    try {
-      await this.doSaveVideo_(
-          {resolution, duration, videoSaver, everPaused: this.everPaused_});
-      state.set(
-          PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false,
-          {resolution, facing: this.facing_});
-    } catch (e) {
-      state.set(
-          PerfEvent.VIDEO_CAPTURE_POST_PROCESSING, false, {hasError: true});
-      throw e;
-    }
-
-    await this.snapshots_.flush();
-  }
-
-  /**
-   * @override
-   */
-  stop_() {
-    if (this.startSound_ && this.startSound_.cancel) {
-      this.startSound_.cancel();
-    }
-    if (this.mediaRecorder_ &&
-        (this.mediaRecorder_.state === 'recording' ||
-         this.mediaRecorder_.state === 'paused')) {
-      this.mediaRecorder_.stop();
-    }
-  }
-
-  /**
-   * Starts recording and waits for stop recording event triggered by stop
-   * shutter.
-   * @return {!Promise<!VideoSaver>} Saves recorded video.
-   * @private
-   */
-  async captureVideo_() {
-    const saver = await this.createVideoSaver_();
-
-    return new Promise((resolve, reject) => {
-      let noChunk = true;
-
-      const ondataavailable = (event) => {
-        if (event.data && event.data.size > 0) {
-          noChunk = false;
-          saver.write(event.data);
-        }
-      };
-      const onstop = (event) => {
-        state.set(state.State.RECORDING, false);
-        state.set(state.State.RECORDING_PAUSED, false);
-        state.set(state.State.RECORDING_UI_PAUSED, false);
-
-        this.mediaRecorder_.removeEventListener(
-            'dataavailable', ondataavailable);
-        this.mediaRecorder_.removeEventListener('stop', onstop);
-
-        if (noChunk) {
-          reject(new Error('Video blob error.'));
-        } else {
-          // TODO(yuli): Handle insufficient storage.
-          resolve(saver);
-        }
-      };
-      const onstart = () => {
-        state.set(state.State.RECORDING, true);
-        this.mediaRecorder_.removeEventListener('start', onstart);
-      };
-      this.mediaRecorder_.addEventListener('dataavailable', ondataavailable);
-      this.mediaRecorder_.addEventListener('stop', onstop);
-      this.mediaRecorder_.addEventListener('start', onstart);
-      this.mediaRecorder_.start(100);
-      state.set(state.State.RECORDING_PAUSED, false);
-      state.set(state.State.RECORDING_UI_PAUSED, false);
-    });
-  }
-}
-
-/**
- * Photo mode capture controller.
- */
-class Photo extends ModeBase {
-  /**
-   * @param {!MediaStream} stream
-   * @param {!Facing} facing
-   * @param {!DoSavePhoto} doSavePhoto
-   * @param {?Resolution} captureResolution
-   * @param {!PlayShutterEffect} playShutterEffect
-   */
-  constructor(
-      stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
-    super(stream, facing, captureResolution);
-
-    /**
-     * Callback for saving picture.
-     * @type {!DoSavePhoto}
-     * @protected
-     */
-    this.doSavePhoto_ = doSavePhoto;
-
-    /**
-     * CrosImageCapture object to capture still photos.
-     * @type {?CrosImageCapture}
-     * @private
-     */
-    this.crosImageCapture_ = null;
-
-    /**
-     * The observer id for saving metadata.
-     * @type {?number}
-     * @private
-     */
-    this.metadataObserverId_ = null;
-
-    /**
-     * Metadata names ready to be saved.
-     * @type {!Array<string>}
-     * @private
-     */
-    this.metadataNames_ = [];
-
-    /**
-     * Callback for playing shutter effect.
-     * @type {!PlayShutterEffect}
-     * @protected
-     */
-    this.playShutterEffect_ = playShutterEffect;
-  }
-
-  /**
-   * @override
-   */
-  async start_() {
-    if (this.crosImageCapture_ === null) {
-      this.crosImageCapture_ =
-          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.playShutterEffect_();
-
-      state.set(PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, true);
-      const blob = await results[0];
-      const image = await util.blobToImage(blob);
-      const resolution = new Resolution(image.width, image.height);
-      await this.doSavePhoto_({resolution, blob}, imageName);
-      state.set(
-          PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false,
-          {resolution, facing: this.facing_});
-    } catch (e) {
-      state.set(PerfEvent.PHOTO_CAPTURE_SHUTTER, false, {hasError: true});
-      state.set(
-          PerfEvent.PHOTO_CAPTURE_POST_PROCESSING, false, {hasError: true});
-      toast.show('error_msg_take_photo_failed');
-      throw e;
-    }
-  }
-
-  /**
-   * Adds an observer to save metadata.
-   * @return {!Promise} Promise for the operation.
-   */
-  async addMetadataObserver() {
-    if (!this.stream_) {
-      return;
-    }
-
-    const deviceOperator = await DeviceOperator.getInstance();
-    if (!deviceOperator) {
-      return;
-    }
-
-    const cameraMetadataTagInverseLookup = {};
-    Object.entries(cros.mojom.CameraMetadataTag).forEach(([key, value]) => {
-      if (key === 'MIN_VALUE' || key === 'MAX_VALUE') {
-        return;
-      }
-      cameraMetadataTagInverseLookup[value] = key;
-    });
-
-    const callback = (metadata) => {
-      const parsedMetadata = {};
-      for (const entry of metadata.entries) {
-        const key = cameraMetadataTagInverseLookup[entry.tag];
-        if (key === undefined) {
-          // TODO(kaihsien): Add support for vendor tags.
-          continue;
-        }
-
-        const val = parseMetadata(entry);
-        parsedMetadata[key] = val;
-      }
-
-      filesystem.saveBlob(
-          new Blob(
-              [JSON.stringify(parsedMetadata, null, 2)],
-              {type: 'application/json'}),
-          this.metadataNames_.shift());
-    };
-
-    const deviceId = this.stream_.getVideoTracks()[0].getSettings().deviceId;
-    this.metadataObserverId_ = await deviceOperator.addMetadataObserver(
-        deviceId, callback, cros.mojom.StreamType.JPEG_OUTPUT);
-  }
-
-  /**
-   * Removes the observer that saves metadata.
-   * @return {!Promise} Promise for the operation.
-   */
-  async removeMetadataObserver() {
-    if (!this.stream_ || this.metadataObserverId_ === null) {
-      return;
-    }
-
-    const deviceOperator = await DeviceOperator.getInstance();
-    if (!deviceOperator) {
-      return;
-    }
-
-    const deviceId = this.stream_.getVideoTracks()[0].getSettings().deviceId;
-    const isSuccess = await deviceOperator.removeMetadataObserver(
-        deviceId, this.metadataObserverId_);
-    if (!isSuccess) {
-      console.error(`Failed to remove metadata observer with id: ${
-          this.metadataObserverId_}`);
-    }
-    this.metadataObserverId_ = null;
-  }
-}
-
-/**
- * Square mode capture controller.
- */
-class Square extends Photo {
-  /**
-   * @param {!MediaStream} stream
-   * @param {!Facing} facing
-   * @param {!DoSavePhoto} doSavePhoto
-   * @param {?Resolution} captureResolution
-   * @param {!PlayShutterEffect} playShutterEffect
-   */
-  constructor(
-      stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
-    super(stream, facing, doSavePhoto, captureResolution, playShutterEffect);
-
-    this.doSavePhoto_ = async (result, ...args) => {
-      // Since the image blob after square cut will lose its EXIF including
-      // orientation information. Corrects the orientation before the square
-      // cut.
-      result.blob = await new Promise(
-          (resolve, reject) => util.orientPhoto(result.blob, resolve, reject));
-      result.blob = await this.cropSquare(result.blob);
-      await doSavePhoto(result, ...args);
-    };
-  }
-
-  /**
-   * Crops out maximum possible centered square from the image blob.
-   * @param {!Blob} blob
-   * @return {!Promise<!Blob>} Promise with result cropped square image.
-   */
-  async cropSquare(blob) {
-    const img = await util.blobToImage(blob);
-    const side = Math.min(img.width, img.height);
-    const canvas = document.createElement('canvas');
-    canvas.width = side;
-    canvas.height = side;
-    const ctx = canvas.getContext('2d');
-    ctx.drawImage(
-        img, Math.floor((img.width - side) / 2),
-        Math.floor((img.height - side) / 2), side, side, 0, 0, side, side);
-    const croppedBlob = await new Promise((resolve) => {
-      canvas.toBlob(resolve, 'image/jpeg');
-    });
-    croppedBlob.resolution = blob.resolution;
-    return croppedBlob;
-  }
-}
-
-/**
- * Portrait mode capture controller.
- */
-class Portrait extends Photo {
-  /**
-   * @param {!MediaStream} stream
-   * @param {!Facing} facing
-   * @param {!DoSavePhoto} doSavePhoto
-   * @param {?Resolution} captureResolution
-   * @param {!PlayShutterEffect} playShutterEffect
-   */
-  constructor(
-      stream, facing, doSavePhoto, captureResolution, playShutterEffect) {
-    super(stream, facing, doSavePhoto, captureResolution, playShutterEffect);
-  }
-
-  /**
-   * @override
-   */
-  async start_() {
-    if (this.crosImageCapture_ === null) {
-      this.crosImageCapture_ =
-          new CrosImageCapture(this.stream_.getVideoTracks()[0]);
-    }
-
-    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 filenamer = new Filenamer();
-    const refImageName = filenamer.newBurstName(false);
-    const portraitImageName = filenamer.newBurstName(true);
-
-    if (this.metadataObserverId_ !== null) {
-      [refImageName, portraitImageName].forEach((/** string */ imageName) => {
-        this.metadataNames_.push(Filenamer.getMetadataName(imageName));
-      });
-    }
-
-    let /** ?Promise<!Blob> */ reference;
-    let /** ?Promise<!Blob> */ portrait;
-
-    try {
-      [reference, portrait] = await this.crosImageCapture_.takePhoto(
-          photoSettings, [cros.mojom.Effect.PORTRAIT_MODE]);
-      this.playShutterEffect_();
-    } catch (e) {
-      toast.show('error_msg_take_photo_failed');
-      throw e;
-    }
-
-    state.set(PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, true);
-    let hasError = false;
-
-    /**
-     * @param {!Promise<!Blob>} p
-     * @param {string} imageName
-     * @return {!Promise}
-     */
-    const saveResult = async (p, imageName) => {
-      const isPortrait = Object.is(p, portrait);
-      let /** ?Blob */ blob = null;
-      try {
-        blob = await p;
-      } catch (e) {
-        hasError = true;
-        toast.show(
-            isPortrait ? 'error_msg_take_portrait_photo_failed' :
-                         'error_msg_take_photo_failed');
-        throw e;
-      }
-      const {width, height} = await util.blobToImage(blob);
-      await this.doSavePhoto_(
-          {resolution: new Resolution(width, height), blob},
-          imageName,
-      );
-    };
-
-    const refSave = saveResult(reference, refImageName);
-    const portraitSave = saveResult(portrait, portraitImageName);
-    try {
-      await portraitSave;
-    } catch (e) {
-      hasError = true;
-      // Portrait image may failed due to absence of human faces.
-      // TODO(inker): Log non-intended error.
-    }
-    await refSave;
-    state.set(
-        PerfEvent.PORTRAIT_MODE_CAPTURE_POST_PROCESSING, false,
-        {hasError, facing: this.facing_});
-  }
-}
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera/review_result.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera/review_result.js
index 492bb4c5..1692759 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera/review_result.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera/review_result.js
@@ -138,7 +138,7 @@
    *     with the video result.
    */
   async openVideo(fileEntry) {
-    this.reviewVideoResult_.src = pictureURL(fileEntry);
+    this.reviewVideoResult_.src = await pictureURL(fileEntry);
     state.set(state.State.REVIEW_VIDEO_RESULT, true);
     state.set(state.State.REVIEW_RESULT, true);
     this.confirmResultButton_.focus();
diff --git a/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js b/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
index bbbe9dd..a5bbdeb 100644
--- a/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
+++ b/chromeos/components/camera_app_ui/resources/src/js/views/camera_intent.js
@@ -25,10 +25,8 @@
 import * as util from '../util.js';
 
 import {Camera} from './camera.js';
-import {
-  PhotoResult,  // eslint-disable-line no-unused-vars
-  VideoResult,  // eslint-disable-line no-unused-vars
-} from './camera/modes.js';
+// eslint-disable-next-line no-unused-vars
+import {PhotoResult, VideoResult} from './camera/mode/index.js';
 import {ReviewResult} from './camera/review_result.js';
 
 /**
@@ -109,7 +107,7 @@
   /**
    * @override
    */
-  async doSavePhoto_(result, name) {
+  async handleResultPhoto(result, name) {
     this.photoResult_ = result;
     try {
       await this.resultSaver_.savePhoto(result.blob, name);
@@ -122,7 +120,7 @@
   /**
    * @override
    */
-  async doSaveVideo_(result) {
+  async handleResultVideo(result) {
     this.videoResult_ = result;
     try {
       await this.resultSaver_.finishSaveVideo(result.videoSaver);
diff --git a/chromeos/components/camera_app_ui/resources/src/views/main.html b/chromeos/components/camera_app_ui/resources/src/views/main.html
index 2abf435..ae76859 100644
--- a/chromeos/components/camera_app_ui/resources/src/views/main.html
+++ b/chromeos/components/camera_app_ui/resources/src/views/main.html
@@ -21,7 +21,7 @@
     <script src="../js/mojo/camera_intent.mojom-lite.js"></script>
     <script src="../js/mojo/camera_app.mojom-lite.js"></script>
     <script src="../js/mojo/camera_app_helper.mojom-lite.js"></script>
-    <script type="module" src="../js/main.js"></script>
+    <script type="module" src="../js/init.js"></script>
   </head>
   <body class="sound mirror mic _3x3">
     <div id="view-camera">
diff --git a/chromeos/components/phonehub/BUILD.gn b/chromeos/components/phonehub/BUILD.gn
index 91bf319..5c3e4c4c 100644
--- a/chromeos/components/phonehub/BUILD.gn
+++ b/chromeos/components/phonehub/BUILD.gn
@@ -18,12 +18,18 @@
     "feature_status_provider_impl.h",
     "mutable_phone_model.cc",
     "mutable_phone_model.h",
+    "notification.cc",
+    "notification.h",
     "notification_access_manager.cc",
     "notification_access_manager.h",
     "notification_access_manager_impl.cc",
     "notification_access_manager_impl.h",
     "notification_access_setup_operation.cc",
     "notification_access_setup_operation.h",
+    "notification_manager.cc",
+    "notification_manager.h",
+    "notification_manager_impl.cc",
+    "notification_manager_impl.h",
     "phone_hub_manager.h",
     "phone_hub_manager_impl.cc",
     "phone_hub_manager_impl.h",
@@ -61,6 +67,8 @@
     "fake_feature_status_provider.h",
     "fake_notification_access_manager.cc",
     "fake_notification_access_manager.h",
+    "fake_notification_manager.cc",
+    "fake_notification_manager.h",
     "fake_phone_hub_manager.cc",
     "fake_phone_hub_manager.h",
     "fake_tether_controller.cc",
@@ -82,6 +90,7 @@
     "feature_status_provider_impl_unittest.cc",
     "mutable_phone_model_unittest.cc",
     "notification_access_manager_impl_unittest.cc",
+    "notification_manager_impl_unittest.cc",
     "phone_status_model_unittest.cc",
     "tether_controller_impl_unittest.cc",
   ]
diff --git a/chromeos/components/phonehub/fake_notification_manager.cc b/chromeos/components/phonehub/fake_notification_manager.cc
new file mode 100644
index 0000000..12491207
--- /dev/null
+++ b/chromeos/components/phonehub/fake_notification_manager.cc
@@ -0,0 +1,88 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/phonehub/fake_notification_manager.h"
+
+#include "base/check.h"
+
+namespace chromeos {
+namespace phonehub {
+
+FakeNotificationManager::InlineReplyMetadata::InlineReplyMetadata(
+    int64_t notification_id,
+    const base::string16& inline_reply_text)
+    : notification_id(notification_id), inline_reply_text(inline_reply_text) {}
+
+FakeNotificationManager::InlineReplyMetadata::~InlineReplyMetadata() = default;
+
+FakeNotificationManager::FakeNotificationManager() = default;
+
+FakeNotificationManager::~FakeNotificationManager() = default;
+
+void FakeNotificationManager::SetNotification(
+    const Notification& notification) {
+  SetNotifications(base::flat_set<Notification>{notification});
+}
+
+void FakeNotificationManager::SetNotifications(
+    const base::flat_set<Notification>& notifications) {
+  base::flat_set<int64_t> added_ids;
+  base::flat_set<int64_t> updated_ids;
+
+  for (const Notification& notification : notifications) {
+    int64_t id = notification.id();
+    auto it = id_to_notification_map_.find(id);
+
+    if (it == id_to_notification_map_.end()) {
+      id_to_notification_map_.emplace(id, notification);
+      added_ids.emplace(id);
+      continue;
+    }
+
+    it->second = notification;
+    updated_ids.emplace(id);
+  }
+
+  NotifyNotificationsAdded(added_ids);
+  NotifyNotificationsUpdated(updated_ids);
+}
+
+void FakeNotificationManager::RemoveNotification(int64_t id) {
+  RemoveNotifications(base::flat_set<int64_t>{id});
+}
+
+void FakeNotificationManager::RemoveNotifications(
+    const base::flat_set<int64_t>& ids) {
+  for (int64_t id : ids) {
+    auto it = id_to_notification_map_.find(id);
+    DCHECK(it != id_to_notification_map_.end());
+    id_to_notification_map_.erase(it);
+  }
+
+  NotifyNotificationsRemoved(ids);
+}
+
+const Notification* FakeNotificationManager::GetNotification(
+    int64_t notification_id) const {
+  auto it = id_to_notification_map_.find(notification_id);
+  if (it == id_to_notification_map_.end())
+    return nullptr;
+  return &it->second;
+}
+
+void FakeNotificationManager::DismissNotification(int64_t notification_id) {
+  DCHECK(base::Contains(id_to_notification_map_, notification_id));
+  dismissed_notification_ids_.push_back(notification_id);
+  NotifyNotificationsRemoved(base::flat_set<int64_t>{notification_id});
+}
+
+void FakeNotificationManager::SendInlineReply(
+    int64_t notification_id,
+    const base::string16& inline_reply_text) {
+  DCHECK(base::Contains(id_to_notification_map_, notification_id));
+  inline_replies_.emplace_back(notification_id, inline_reply_text);
+}
+
+}  // namespace phonehub
+}  // namespace chromeos
diff --git a/chromeos/components/phonehub/fake_notification_manager.h b/chromeos/components/phonehub/fake_notification_manager.h
new file mode 100644
index 0000000..5d2a9ea
--- /dev/null
+++ b/chromeos/components/phonehub/fake_notification_manager.h
@@ -0,0 +1,61 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_PHONEHUB_FAKE_NOTIFICATION_MANAGER_H_
+#define CHROMEOS_COMPONENTS_PHONEHUB_FAKE_NOTIFICATION_MANAGER_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "chromeos/components/phonehub/notification.h"
+#include "chromeos/components/phonehub/notification_manager.h"
+
+namespace chromeos {
+namespace phonehub {
+
+class FakeNotificationManager : public NotificationManager {
+ public:
+  FakeNotificationManager();
+  ~FakeNotificationManager() override;
+
+  void SetNotification(const Notification& notification);
+  void SetNotifications(const base::flat_set<Notification>& notifications);
+
+  void RemoveNotification(int64_t id);
+  void RemoveNotifications(const base::flat_set<int64_t>& ids);
+
+  const std::vector<int64_t>& dismissed_notification_ids() const {
+    return dismissed_notification_ids_;
+  }
+
+  struct InlineReplyMetadata {
+    InlineReplyMetadata(int64_t notification_id,
+                        const base::string16& inline_reply_text);
+    ~InlineReplyMetadata();
+
+    int64_t notification_id;
+    base::string16 inline_reply_text;
+  };
+
+  const std::vector<InlineReplyMetadata>& inline_replies() const {
+    return inline_replies_;
+  }
+
+ private:
+  // NotificationManager:
+  const Notification* GetNotification(int64_t notification_id) const override;
+  void DismissNotification(int64_t notification_id) override;
+  void SendInlineReply(int64_t notification_id,
+                       const base::string16& inline_reply_text) override;
+
+  std::unordered_map<int64_t, Notification> id_to_notification_map_;
+  std::vector<int64_t> dismissed_notification_ids_;
+  std::vector<InlineReplyMetadata> inline_replies_;
+};
+
+}  // namespace phonehub
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PHONEHUB_FAKE_NOTIFICATION_MANAGER_H_
diff --git a/chromeos/components/phonehub/fake_phone_hub_manager.cc b/chromeos/components/phonehub/fake_phone_hub_manager.cc
index 219d344..97c7463 100644
--- a/chromeos/components/phonehub/fake_phone_hub_manager.cc
+++ b/chromeos/components/phonehub/fake_phone_hub_manager.cc
@@ -4,38 +4,31 @@
 
 #include "chromeos/components/phonehub/fake_phone_hub_manager.h"
 
-#include "chromeos/components/phonehub/fake_feature_status_provider.h"
-#include "chromeos/components/phonehub/fake_notification_access_manager.h"
-#include "chromeos/components/phonehub/fake_tether_controller.h"
-#include "chromeos/components/phonehub/mutable_phone_model.h"
-
 namespace chromeos {
 namespace phonehub {
 
-FakePhoneHubManager::FakePhoneHubManager()
-    : fake_feature_status_provider_(
-          std::make_unique<FakeFeatureStatusProvider>()),
-      fake_notification_access_manager_(
-          std::make_unique<FakeNotificationAccessManager>()),
-      mutable_phone_model_(std::make_unique<MutablePhoneModel>()),
-      fake_tether_controller_(std::make_unique<FakeTetherController>()) {}
+FakePhoneHubManager::FakePhoneHubManager() = default;
 
 FakePhoneHubManager::~FakePhoneHubManager() = default;
 
 FeatureStatusProvider* FakePhoneHubManager::GetFeatureStatusProvider() {
-  return fake_feature_status_provider_.get();
+  return &fake_feature_status_provider_;
 }
 
 NotificationAccessManager* FakePhoneHubManager::GetNotificationAccessManager() {
-  return fake_notification_access_manager_.get();
+  return &fake_notification_access_manager_;
+}
+
+NotificationManager* FakePhoneHubManager::GetNotificationManager() {
+  return &fake_notification_manager_;
 }
 
 PhoneModel* FakePhoneHubManager::GetPhoneModel() {
-  return mutable_phone_model_.get();
+  return &mutable_phone_model_;
 }
 
 TetherController* FakePhoneHubManager::GetTetherController() {
-  return fake_tether_controller_.get();
+  return &fake_tether_controller_;
 }
 
 }  // namespace phonehub
diff --git a/chromeos/components/phonehub/fake_phone_hub_manager.h b/chromeos/components/phonehub/fake_phone_hub_manager.h
index 23b5ba93..309bff8 100644
--- a/chromeos/components/phonehub/fake_phone_hub_manager.h
+++ b/chromeos/components/phonehub/fake_phone_hub_manager.h
@@ -7,17 +7,16 @@
 
 #include <memory>
 
+#include "chromeos/components/phonehub/fake_feature_status_provider.h"
+#include "chromeos/components/phonehub/fake_notification_access_manager.h"
+#include "chromeos/components/phonehub/fake_notification_manager.h"
+#include "chromeos/components/phonehub/fake_tether_controller.h"
+#include "chromeos/components/phonehub/mutable_phone_model.h"
 #include "chromeos/components/phonehub/phone_hub_manager.h"
 
 namespace chromeos {
-
 namespace phonehub {
 
-class FakeFeatureStatusProvider;
-class FakeNotificationAccessManager;
-class MutablePhoneModel;
-class FakeTetherController;
-
 // This class initializes fake versions of the core business logic of Phone Hub.
 class FakePhoneHubManager : public PhoneHubManager {
  public:
@@ -25,33 +24,36 @@
   ~FakePhoneHubManager() override;
 
   FakeFeatureStatusProvider* fake_feature_status_provider() {
-    return fake_feature_status_provider_.get();
+    return &fake_feature_status_provider_;
   }
 
   FakeNotificationAccessManager* fake_notification_access_manager() {
-    return fake_notification_access_manager_.get();
+    return &fake_notification_access_manager_;
   }
 
-  MutablePhoneModel* mutable_phone_model() {
-    return mutable_phone_model_.get();
+  FakeNotificationManager* fake_notification_manager() {
+    return &fake_notification_manager_;
   }
 
+  MutablePhoneModel* mutable_phone_model() { return &mutable_phone_model_; }
+
   FakeTetherController* fake_tether_controller() {
-    return fake_tether_controller_.get();
+    return &fake_tether_controller_;
   }
 
  private:
   // PhoneHubManager:
   FeatureStatusProvider* GetFeatureStatusProvider() override;
   NotificationAccessManager* GetNotificationAccessManager() override;
+  NotificationManager* GetNotificationManager() override;
   PhoneModel* GetPhoneModel() override;
   TetherController* GetTetherController() override;
 
-  std::unique_ptr<FakeFeatureStatusProvider> fake_feature_status_provider_;
-  std::unique_ptr<FakeNotificationAccessManager>
-      fake_notification_access_manager_;
-  std::unique_ptr<MutablePhoneModel> mutable_phone_model_;
-  std::unique_ptr<FakeTetherController> fake_tether_controller_;
+  FakeFeatureStatusProvider fake_feature_status_provider_;
+  FakeNotificationAccessManager fake_notification_access_manager_;
+  FakeNotificationManager fake_notification_manager_;
+  MutablePhoneModel mutable_phone_model_;
+  FakeTetherController fake_tether_controller_;
 };
 
 }  // namespace phonehub
diff --git a/chromeos/components/phonehub/notification.cc b/chromeos/components/phonehub/notification.cc
new file mode 100644
index 0000000..2b0060f
--- /dev/null
+++ b/chromeos/components/phonehub/notification.cc
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/phonehub/notification.h"
+
+#include <tuple>
+
+namespace chromeos {
+namespace phonehub {
+
+Notification::AppMetadata::AppMetadata(const base::string16& visible_app_name,
+                                       const std::string& package_name,
+                                       const gfx::Image& icon)
+    : visible_app_name(visible_app_name),
+      package_name(package_name),
+      icon(icon) {}
+
+Notification::AppMetadata::AppMetadata(const AppMetadata& other) = default;
+
+bool Notification::AppMetadata::operator==(const AppMetadata& other) const {
+  return visible_app_name == other.visible_app_name &&
+         package_name == other.package_name && icon == other.icon;
+}
+
+bool Notification::AppMetadata::operator!=(const AppMetadata& other) const {
+  return !(*this == other);
+}
+
+Notification::Notification(int64_t id,
+                           const AppMetadata& app_metadata,
+                           const base::Time& timestamp,
+                           Importance importance,
+                           int64_t inline_reply_id,
+                           const base::Optional<base::string16>& title,
+                           const base::Optional<base::string16>& text_content,
+                           const base::Optional<gfx::Image>& shared_image,
+                           const base::Optional<gfx::Image>& contact_image)
+    : id_(id),
+      app_metadata_(app_metadata),
+      timestamp_(timestamp),
+      importance_(importance),
+      inline_reply_id_(inline_reply_id),
+      title_(title),
+      text_content_(text_content),
+      shared_image_(shared_image),
+      contact_image_(contact_image) {}
+
+Notification::Notification(const Notification& other) = default;
+
+Notification::~Notification() = default;
+
+bool Notification::operator<(const Notification& other) const {
+  return std::tie(timestamp_, id_) < std::tie(other.timestamp_, other.id_);
+}
+
+bool Notification::operator==(const Notification& other) const {
+  return id_ == other.id_ && app_metadata_ == other.app_metadata_ &&
+         timestamp_ == other.timestamp_ && importance_ == other.importance_ &&
+         inline_reply_id_ == other.inline_reply_id_ && title_ == other.title_ &&
+         text_content_ == other.text_content_ &&
+         shared_image_ == other.shared_image_ &&
+         contact_image_ == other.contact_image_;
+}
+
+bool Notification::operator!=(const Notification& other) const {
+  return !(*this == other);
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const Notification::AppMetadata& app_metadata) {
+  stream << "{VisibleAppName: \"" << app_metadata.visible_app_name << "\", "
+         << "PackageName: \"" << app_metadata.package_name << "\"}";
+  return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         Notification::Importance importance) {
+  switch (importance) {
+    case Notification::Importance::kUnspecified:
+      stream << "[Unspecified]";
+      break;
+    case Notification::Importance::kNone:
+      stream << "[None]";
+      break;
+    case Notification::Importance::kMin:
+      stream << "[Min]";
+      break;
+    case Notification::Importance::kLow:
+      stream << "[Low]";
+      break;
+    case Notification::Importance::kDefault:
+      stream << "[Default]";
+      break;
+    case Notification::Importance::kHigh:
+      stream << "[High]";
+      break;
+  }
+  return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream,
+                         const Notification& notification) {
+  stream << "{Id: " << notification.id() << ", "
+         << "App: " << notification.app_metadata() << ", "
+         << "Timestamp: " << notification.timestamp() << ", "
+         << "Importance: " << notification.importance() << "}";
+  return stream;
+}
+
+}  // namespace phonehub
+}  // namespace chromeos
diff --git a/chromeos/components/phonehub/notification.h b/chromeos/components/phonehub/notification.h
new file mode 100644
index 0000000..42df1cd
--- /dev/null
+++ b/chromeos/components/phonehub/notification.h
@@ -0,0 +1,122 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_H_
+#define CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_H_
+
+#include <stdint.h>
+#include <ostream>
+#include <string>
+
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "ui/gfx/image/image.h"
+
+namespace chromeos {
+namespace phonehub {
+
+// A notification generated on the phone, whose contents are transferred to
+// Chrome OS via a Phone Hub connection. Notifications in Phone Hub support
+// inline reply and images.
+class Notification {
+ public:
+  // Describes the app which generates a notification.
+  struct AppMetadata {
+    AppMetadata(const base::string16& visible_app_name,
+                const std::string& package_name,
+                const gfx::Image& icon);
+    AppMetadata(const AppMetadata& other);
+
+    bool operator==(const AppMetadata& other) const;
+    bool operator!=(const AppMetadata& other) const;
+
+    base::string16 visible_app_name;
+    std::string package_name;
+    gfx::Image icon;
+  };
+
+  // Notification importance; for more details, see
+  // https://developer.android.com/reference/android/app/NotificationManager.
+  enum class Importance {
+    // Older versions of Android do not specify an importance level.
+    kUnspecified,
+
+    // Does not show in the Android notification shade.
+    kNone,
+
+    // Shows in the Android notification shade, below the fold.
+    kMin,
+
+    // Shows in the Android notification shade and potentially status bar, but
+    // is not audibly intrusive.
+    kLow,
+
+    // Shows in the Android notification shade and status bar and makes noise,
+    // but does not visually intrude.
+    kDefault,
+
+    // Shows in the Android notification shade and status bar, makes noise, and
+    // "peeks" down onto the screen when received.
+    kHigh
+  };
+
+  // Note: A notification should include at least one of |title|,
+  // |text_content|, and |shared_image| so that it can be rendered in the UI.
+  Notification(
+      int64_t id,
+      const AppMetadata& app_metadata,
+      const base::Time& timestamp,
+      Importance importance,
+      int64_t inline_reply_id,
+      const base::Optional<base::string16>& title = base::nullopt,
+      const base::Optional<base::string16>& text_content = base::nullopt,
+      const base::Optional<gfx::Image>& shared_image = base::nullopt,
+      const base::Optional<gfx::Image>& contact_image = base::nullopt);
+  Notification(const Notification& other);
+  ~Notification();
+
+  bool operator<(const Notification& other) const;
+  bool operator==(const Notification& other) const;
+  bool operator!=(const Notification& other) const;
+
+  int64_t id() const { return id_; }
+  const AppMetadata& app_metadata() const { return app_metadata_; }
+  base::Time timestamp() const { return timestamp_; }
+  Importance importance() const { return importance_; }
+  int64_t inline_reply_id() const { return inline_reply_id_; }
+  const base::Optional<base::string16>& title() const { return title_; }
+  const base::Optional<base::string16>& text_content() const {
+    return text_content_;
+  }
+  const base::Optional<gfx::Image>& shared_image() const {
+    return shared_image_;
+  }
+  const base::Optional<gfx::Image>& contact_image() const {
+    return contact_image_;
+  }
+
+ private:
+  int64_t id_;
+  AppMetadata app_metadata_;
+  base::Time timestamp_;
+  Importance importance_;
+  int64_t inline_reply_id_;
+  base::Optional<base::string16> title_;
+  base::Optional<base::string16> text_content_;
+  base::Optional<gfx::Image> shared_image_;
+  base::Optional<gfx::Image> contact_image_;
+};
+
+std::ostream& operator<<(std::ostream& stream,
+                         const Notification::AppMetadata& app_metadata);
+std::ostream& operator<<(std::ostream& stream,
+                         Notification::Importance importance);
+std::ostream& operator<<(std::ostream& stream,
+                         const Notification& notification);
+
+}  // namespace phonehub
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_H_
diff --git a/chromeos/components/phonehub/notification_manager.cc b/chromeos/components/phonehub/notification_manager.cc
new file mode 100644
index 0000000..7173b153
--- /dev/null
+++ b/chromeos/components/phonehub/notification_manager.cc
@@ -0,0 +1,41 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/phonehub/notification_manager.h"
+
+namespace chromeos {
+namespace phonehub {
+
+NotificationManager::NotificationManager() = default;
+
+NotificationManager::~NotificationManager() = default;
+
+void NotificationManager::AddObserver(Observer* observer) {
+  observer_list_.AddObserver(observer);
+}
+
+void NotificationManager::RemoveObserver(Observer* observer) {
+  observer_list_.RemoveObserver(observer);
+}
+
+void NotificationManager::NotifyNotificationsAdded(
+    const base::flat_set<int64_t>& notification_ids) {
+  for (auto& observer : observer_list_)
+    observer.OnNotificationsAdded(notification_ids);
+}
+
+void NotificationManager::NotifyNotificationsUpdated(
+    const base::flat_set<int64_t>& notification_ids) {
+  for (auto& observer : observer_list_)
+    observer.OnNotificationsUpdated(notification_ids);
+}
+
+void NotificationManager::NotifyNotificationsRemoved(
+    const base::flat_set<int64_t>& notification_ids) {
+  for (auto& observer : observer_list_)
+    observer.OnNotificationsRemoved(notification_ids);
+}
+
+}  // namespace phonehub
+}  // namespace chromeos
diff --git a/chromeos/components/phonehub/notification_manager.h b/chromeos/components/phonehub/notification_manager.h
new file mode 100644
index 0000000..8b646bf
--- /dev/null
+++ b/chromeos/components/phonehub/notification_manager.h
@@ -0,0 +1,79 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_H_
+#define CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_H_
+
+#include <stdint.h>
+
+#include "base/containers/flat_set.h"
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
+
+namespace chromeos {
+namespace phonehub {
+
+class Notification;
+
+// Tracks notifications which have been synced from a connected phone during a
+// Phone Hub session. Clients can access notifications via GetNotification() and
+// can be notified when the state of notifications changes by registering as
+// observers.
+//
+// This class also provides functionality for interacting with notifications;
+// namely, clients can dismiss notifications or send inline replies.
+class NotificationManager {
+ public:
+  class Observer : public base::CheckedObserver {
+   public:
+    ~Observer() override = default;
+
+    virtual void OnNotificationsAdded(
+        const base::flat_set<int64_t>& notification_ids) {}
+    virtual void OnNotificationsUpdated(
+        const base::flat_set<int64_t>& notification_ids) {}
+    virtual void OnNotificationsRemoved(
+        const base::flat_set<int64_t>& notification_ids) {}
+  };
+
+  NotificationManager(const NotificationManager&) = delete;
+  NotificationManager& operator=(const NotificationManager&) = delete;
+  virtual ~NotificationManager();
+
+  // Returns null if no notification exists with the given ID. Pointers returned
+  // by this function should not be cached, since the underlying Notification
+  // object may be deleted by a future update.
+  virtual const Notification* GetNotification(
+      int64_t notification_id) const = 0;
+
+  // Dismisses the notification with the given ID; if no notification exists
+  // with this ID, this function is a no-op.
+  virtual void DismissNotification(int64_t notification_id) = 0;
+
+  // Sends an inline reply for the notificaiton with the given ID; if no
+  // notification exists with this ID, this function is a no-op.
+  virtual void SendInlineReply(int64_t notification_id,
+                               const base::string16& inline_reply_text) = 0;
+
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+ protected:
+  NotificationManager();
+
+  void NotifyNotificationsAdded(
+      const base::flat_set<int64_t>& notification_ids);
+  void NotifyNotificationsUpdated(
+      const base::flat_set<int64_t>& notification_ids);
+  void NotifyNotificationsRemoved(
+      const base::flat_set<int64_t>& notification_ids);
+
+ private:
+  base::ObserverList<Observer> observer_list_;
+};
+
+}  // namespace phonehub
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_H_
diff --git a/chromeos/components/phonehub/notification_manager_impl.cc b/chromeos/components/phonehub/notification_manager_impl.cc
new file mode 100644
index 0000000..a0db288a
--- /dev/null
+++ b/chromeos/components/phonehub/notification_manager_impl.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/phonehub/notification_manager_impl.h"
+
+#include "chromeos/components/multidevice/logging/logging.h"
+
+namespace chromeos {
+namespace phonehub {
+
+NotificationManagerImpl::NotificationManagerImpl() = default;
+
+NotificationManagerImpl::~NotificationManagerImpl() = default;
+
+const Notification* NotificationManagerImpl::GetNotification(
+    int64_t notification_id) const {
+  return nullptr;
+}
+
+void NotificationManagerImpl::DismissNotification(int64_t notification_id) {
+  PA_LOG(INFO) << "Dismissing notification with ID " << notification_id << ".";
+}
+
+void NotificationManagerImpl::SendInlineReply(
+    int64_t notification_id,
+    const base::string16& inline_reply_text) {
+  PA_LOG(INFO) << "Sending inline reply for notification with ID "
+               << notification_id << ".";
+}
+
+}  // namespace phonehub
+}  // namespace chromeos
diff --git a/chromeos/components/phonehub/notification_manager_impl.h b/chromeos/components/phonehub/notification_manager_impl.h
new file mode 100644
index 0000000..e37fe52a2
--- /dev/null
+++ b/chromeos/components/phonehub/notification_manager_impl.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_IMPL_H_
+#define CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_IMPL_H_
+
+#include "chromeos/components/phonehub/notification_manager.h"
+
+namespace chromeos {
+namespace phonehub {
+
+// TODO(https://crbug.com/1106937): Add real implementation.
+class NotificationManagerImpl : public NotificationManager {
+ public:
+  NotificationManagerImpl();
+  ~NotificationManagerImpl() override;
+
+ private:
+  // NotificationManager:
+  const Notification* GetNotification(int64_t notification_id) const override;
+  void DismissNotification(int64_t notification_id) override;
+  void SendInlineReply(int64_t notification_id,
+                       const base::string16& inline_reply_text) override;
+};
+
+}  // namespace phonehub
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_PHONEHUB_NOTIFICATION_MANAGER_IMPL_H_
diff --git a/chromeos/components/phonehub/notification_manager_impl_unittest.cc b/chromeos/components/phonehub/notification_manager_impl_unittest.cc
new file mode 100644
index 0000000..7efccde
--- /dev/null
+++ b/chromeos/components/phonehub/notification_manager_impl_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/phonehub/notification_manager_impl.h"
+
+#include <memory>
+
+#include "base/containers/flat_map.h"
+#include "base/optional.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace phonehub {
+namespace {
+
+enum class NotificationState { kAdded, kUpdated, kRemoved };
+
+class FakeObserver : public NotificationManager::Observer {
+ public:
+  FakeObserver() = default;
+  ~FakeObserver() override = default;
+
+  base::Optional<NotificationState> GetState(int64_t notification_id) const {
+    const auto it = id_to_state_map_.find(notification_id);
+    if (it == id_to_state_map_.end())
+      return base::nullopt;
+    return it->second;
+  }
+
+ private:
+  // NotificationManager::Observer:
+  void OnNotificationsAdded(
+      const base::flat_set<int64_t>& notification_ids) override {
+    for (int64_t id : notification_ids)
+      id_to_state_map_[id] = NotificationState::kAdded;
+  }
+
+  void OnNotificationsUpdated(
+      const base::flat_set<int64_t>& notification_ids) override {
+    for (int64_t id : notification_ids)
+      id_to_state_map_[id] = NotificationState::kUpdated;
+  }
+
+  void OnNotificationsRemoved(
+      const base::flat_set<int64_t>& notification_ids) override {
+    for (int64_t id : notification_ids)
+      id_to_state_map_[id] = NotificationState::kRemoved;
+  }
+
+  base::flat_map<int64_t, NotificationState> id_to_state_map_;
+};
+
+}  // namespace
+
+class NotificationManagerImplTest : public testing::Test {
+ protected:
+  NotificationManagerImplTest() = default;
+  NotificationManagerImplTest(const NotificationManagerImplTest&) = delete;
+  NotificationManagerImplTest& operator=(const NotificationManagerImplTest&) =
+      delete;
+  ~NotificationManagerImplTest() override = default;
+
+  // testing::Test:
+  void SetUp() override {
+    manager_ = std::make_unique<NotificationManagerImpl>();
+    manager_->AddObserver(&fake_observer_);
+  }
+
+  void TearDown() override { manager_->RemoveObserver(&fake_observer_); }
+
+  NotificationManager& manager() { return *manager_; }
+
+ private:
+  FakeObserver fake_observer_;
+  std::unique_ptr<NotificationManager> manager_;
+};
+
+// TODO(khorimoto): Remove this test once we have real functionality to test.
+TEST_F(NotificationManagerImplTest, Initialize) {
+  EXPECT_FALSE(manager().GetNotification(/*notification_id=*/0));
+}
+
+}  // namespace phonehub
+}  // namespace chromeos
diff --git a/chromeos/components/phonehub/phone_hub_manager.h b/chromeos/components/phonehub/phone_hub_manager.h
index ff3994d..b5efc0cc 100644
--- a/chromeos/components/phonehub/phone_hub_manager.h
+++ b/chromeos/components/phonehub/phone_hub_manager.h
@@ -10,6 +10,7 @@
 
 class FeatureStatusProvider;
 class NotificationAccessManager;
+class NotificationManager;
 class PhoneModel;
 class TetherController;
 
@@ -22,12 +23,11 @@
   PhoneHubManager(const PhoneHubManager&) = delete;
   PhoneHubManager& operator=(const PhoneHubManager&) = delete;
 
+  // Getters for sub-elements.
   virtual FeatureStatusProvider* GetFeatureStatusProvider() = 0;
-
   virtual NotificationAccessManager* GetNotificationAccessManager() = 0;
-
+  virtual NotificationManager* GetNotificationManager() = 0;
   virtual PhoneModel* GetPhoneModel() = 0;
-
   virtual TetherController* GetTetherController() = 0;
 
  protected:
diff --git a/chromeos/components/phonehub/phone_hub_manager_impl.cc b/chromeos/components/phonehub/phone_hub_manager_impl.cc
index 0bc4b9d..60e8bc4 100644
--- a/chromeos/components/phonehub/phone_hub_manager_impl.cc
+++ b/chromeos/components/phonehub/phone_hub_manager_impl.cc
@@ -7,6 +7,7 @@
 #include "chromeos/components/phonehub/feature_status_provider_impl.h"
 #include "chromeos/components/phonehub/mutable_phone_model.h"
 #include "chromeos/components/phonehub/notification_access_manager_impl.h"
+#include "chromeos/components/phonehub/notification_manager_impl.h"
 #include "chromeos/components/phonehub/tether_controller_impl.h"
 
 namespace chromeos {
@@ -21,6 +22,7 @@
           multidevice_setup_client)),
       notification_access_manager_(
           std::make_unique<NotificationAccessManagerImpl>(pref_service)),
+      notification_manager_(std::make_unique<NotificationManagerImpl>()),
       phone_model_(std::make_unique<MutablePhoneModel>()),
       tether_controller_(
           std::make_unique<TetherControllerImpl>(multidevice_setup_client)) {}
@@ -35,6 +37,10 @@
   return notification_access_manager_.get();
 }
 
+NotificationManager* PhoneHubManagerImpl::GetNotificationManager() {
+  return notification_manager_.get();
+}
+
 PhoneModel* PhoneHubManagerImpl::GetPhoneModel() {
   return phone_model_.get();
 }
diff --git a/chromeos/components/phonehub/phone_hub_manager_impl.h b/chromeos/components/phonehub/phone_hub_manager_impl.h
index 57cb3bcd..708afec 100644
--- a/chromeos/components/phonehub/phone_hub_manager_impl.h
+++ b/chromeos/components/phonehub/phone_hub_manager_impl.h
@@ -36,6 +36,7 @@
   // PhoneHubManager:
   FeatureStatusProvider* GetFeatureStatusProvider() override;
   NotificationAccessManager* GetNotificationAccessManager() override;
+  NotificationManager* GetNotificationManager() override;
   PhoneModel* GetPhoneModel() override;
   TetherController* GetTetherController() override;
 
@@ -45,6 +46,7 @@
 
   std::unique_ptr<FeatureStatusProvider> feature_status_provider_;
   std::unique_ptr<NotificationAccessManager> notification_access_manager_;
+  std::unique_ptr<NotificationManager> notification_manager_;
   std::unique_ptr<PhoneModel> phone_model_;
   std::unique_ptr<TetherController> tether_controller_;
 };
diff --git a/chromeos/components/phonehub/phone_model_test_util.cc b/chromeos/components/phonehub/phone_model_test_util.cc
index 1e728e4..445a28c 100644
--- a/chromeos/components/phonehub/phone_model_test_util.cc
+++ b/chromeos/components/phonehub/phone_model_test_util.cc
@@ -12,12 +12,6 @@
 
 const char kFakeMobileProviderName[] = "Fake Mobile Provider";
 
-const char kFakeBrowserTabUrl1[] = "https://www.example.com/tab1";
-const char kFakeBrowserTabName1[] = "Tab 1";
-
-const char kFakeBrowserTabUrl2[] = "https://www.example.com/tab2";
-const char kFakeBrowserTabName2[] = "Tab 2";
-
 const PhoneStatusModel::MobileConnectionMetadata&
 CreateFakeMobileConnectionMetadata() {
   static const base::NoDestructor<PhoneStatusModel::MobileConnectionMetadata>
@@ -37,6 +31,11 @@
   return *fake_phone_status_model;
 }
 
+const char kFakeBrowserTabUrl1[] = "https://www.example.com/tab1";
+const char kFakeBrowserTabName1[] = "Tab 1";
+const char kFakeBrowserTabUrl2[] = "https://www.example.com/tab2";
+const char kFakeBrowserTabName2[] = "Tab 2";
+
 const BrowserTabsModel::BrowserTabMetadata& CreateFakeBrowserTabMetadata() {
   static const base::NoDestructor<BrowserTabsModel::BrowserTabMetadata>
       fake_browser_tab_metadata{GURL(kFakeBrowserTabUrl1),
@@ -58,5 +57,31 @@
   return *fake_browser_tabs_model;
 }
 
+const char kFakeAppVisibleName[] = "Fake App";
+const char kFakeAppPackageName[] = "com.fakeapp";
+const int64_t kFakeAppId = 1234567890;
+const int64_t kFakeInlineReplyId = 1337;
+const char kFakeNotificationTitle[] = "Fake Title";
+const char kFakeNotificationText[] = "Fake Text";
+
+const Notification::AppMetadata& CreateFakeAppMetadata() {
+  static const base::NoDestructor<Notification::AppMetadata> fake_app_metadata{
+      base::UTF8ToUTF16(kFakeAppVisibleName), kFakeAppPackageName,
+      gfx::Image()};
+  return *fake_app_metadata;
+}
+
+const Notification& CreateFakeNotification() {
+  static const base::NoDestructor<Notification> fake_notification{
+      kFakeAppId,
+      CreateFakeAppMetadata(),
+      base::Time(),
+      Notification::Importance::kDefault,
+      kFakeInlineReplyId,
+      base::UTF8ToUTF16(kFakeNotificationTitle),
+      base::UTF8ToUTF16(kFakeNotificationText)};
+  return *fake_notification;
+}
+
 }  // namespace phonehub
 }  // namespace chromeos
diff --git a/chromeos/components/phonehub/phone_model_test_util.h b/chromeos/components/phonehub/phone_model_test_util.h
index e3d3073a..8a831f37 100644
--- a/chromeos/components/phonehub/phone_model_test_util.h
+++ b/chromeos/components/phonehub/phone_model_test_util.h
@@ -5,29 +5,45 @@
 #ifndef CHROMEOS_COMPONENTS_PHONEHUB_PHONE_MODEL_TEST_UTIL_H_
 #define CHROMEOS_COMPONENTS_PHONEHUB_PHONE_MODEL_TEST_UTIL_H_
 
+#include <stdint.h>
+
 #include "chromeos/components/phonehub/browser_tabs_model.h"
+#include "chromeos/components/phonehub/notification.h"
 #include "chromeos/components/phonehub/phone_status_model.h"
 
 namespace chromeos {
 namespace phonehub {
 
+// Fake data for phone status.
 extern const char kFakeMobileProviderName[];
 
-extern const char kFakeBrowserTabUrl1[];
-extern const char kFakeBrowserTabName1[];
-
-extern const char kFakeBrowserTabUrl2[];
-extern const char kFakeBrowserTabName2[];
-
 // Creates fake phone status data for use in tests.
 const PhoneStatusModel::MobileConnectionMetadata&
 CreateFakeMobileConnectionMetadata();
 const PhoneStatusModel& CreateFakePhoneStatusModel();
 
+// Fake data for browser tabs.
+extern const char kFakeBrowserTabUrl1[];
+extern const char kFakeBrowserTabName1[];
+extern const char kFakeBrowserTabUrl2[];
+extern const char kFakeBrowserTabName2[];
+
 // Creates fake browser tab data for use in tests.
 const BrowserTabsModel::BrowserTabMetadata& CreateFakeBrowserTabMetadata();
 const BrowserTabsModel& CreateFakeBrowserTabsModel();
 
+// Fake data for notifications.
+extern const char kFakeAppVisibleName[];
+extern const char kFakeAppPackageName[];
+extern const int64_t kFakeAppId;
+extern const int64_t kFakeInlineReplyId;
+extern const char kFakeNotificationTitle[];
+extern const char kFakeNotificationText[];
+
+// Creates fake notification data for use in tests.
+const Notification::AppMetadata& CreateFakeAppMetadata();
+const Notification& CreateFakeNotification();
+
 }  // namespace phonehub
 }  // namespace chromeos
 
diff --git a/chromeos/components/telemetry_extension_ui/BUILD.gn b/chromeos/components/telemetry_extension_ui/BUILD.gn
index 2fc8496..9e5e0cb 100644
--- a/chromeos/components/telemetry_extension_ui/BUILD.gn
+++ b/chromeos/components/telemetry_extension_ui/BUILD.gn
@@ -8,6 +8,7 @@
 
 source_set("telemetry_extension_ui") {
   sources = [
+    "convert_ptr.h",
     "diagnostics_service.cc",
     "diagnostics_service.h",
     "diagnostics_service_converters.cc",
@@ -41,6 +42,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "convert_ptr_unittest.cc",
     "diagnostics_service_converters_unittest.cc",
     "probe_service_converters_unittest.cc",
     "probe_service_unittest.cc",
diff --git a/chromeos/components/telemetry_extension_ui/convert_ptr.h b/chromeos/components/telemetry_extension_ui/convert_ptr.h
new file mode 100644
index 0000000..6ddb492
--- /dev/null
+++ b/chromeos/components/telemetry_extension_ui/convert_ptr.h
@@ -0,0 +1,32 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_TELEMETRY_EXTENSION_UI_CONVERT_PTR_H_
+#define CHROMEOS_COMPONENTS_TELEMETRY_EXTENSION_UI_CONVERT_PTR_H_
+
+#if defined(OFFICIAL_BUILD)
+#error ConvertPtr should only be included in unofficial builds.
+#endif
+
+#include <utility>
+
+#include "chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h"
+#include "chromeos/components/telemetry_extension_ui/probe_service_converters.h"
+
+// To use ConvertPtr with other functions, headers to function definitions
+// must be included in this file.
+
+namespace chromeos {
+namespace converters {
+
+template <class InputT>
+auto ConvertPtr(InputT input) {
+  return (!input.is_null()) ? unchecked::UncheckedConvertPtr(std::move(input))
+                            : nullptr;
+}
+
+}  // namespace converters
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TELEMETRY_EXTENSION_UI_CONVERT_PTR_H_
diff --git a/chromeos/components/telemetry_extension_ui/convert_ptr_unittest.cc b/chromeos/components/telemetry_extension_ui/convert_ptr_unittest.cc
new file mode 100644
index 0000000..26483b1
--- /dev/null
+++ b/chromeos/components/telemetry_extension_ui/convert_ptr_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
+
+#include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"
+#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace converters {
+
+// Tests that |ConvertPtr| function returns nullptr if input is nullptr.
+// ConvertPtr is a template, so we can test this function with any valid type.
+TEST(TelemetryConvertPtr, ConvertPtrTakesNullPtr) {
+  EXPECT_TRUE(ConvertPtr(cros_healthd::mojom::ProbeErrorPtr()).is_null());
+}
+
+}  // namespace converters
+}  // namespace chromeos
\ No newline at end of file
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
index 89347c3..b3370215 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
 #include "chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h"
 #include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
@@ -42,8 +43,7 @@
              callback,
          const std::vector<cros_healthd::mojom::DiagnosticRoutineEnum>&
              routines) {
-        std::move(callback).Run(
-            diagnostics_service_converters::Convert(routines));
+        std::move(callback).Run(converters::Convert(routines));
       },
       std::move(callback)));
 }
@@ -54,13 +54,12 @@
     bool include_output,
     GetRoutineUpdateCallback callback) {
   GetService()->GetRoutineUpdate(
-      id, diagnostics_service_converters::Convert(command), include_output,
+      id, converters::Convert(command), include_output,
       base::BindOnce(
           [](health::mojom::DiagnosticsService::GetRoutineUpdateCallback
                  callback,
              cros_healthd::mojom::RoutineUpdatePtr ptr) {
-            std::move(callback).Run(
-                diagnostics_service_converters::ConvertPtr(std::move(ptr)));
+            std::move(callback).Run(converters::ConvertPtr(std::move(ptr)));
           },
           std::move(callback)));
 }
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
index 7b65dfc5..77372f6 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.cc
@@ -7,11 +7,12 @@
 #include "base/notreached.h"
 #include "base/optional.h"
 #include "chrome/browser/chromeos/wilco_dtc_supportd/mojo_utils.h"
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
 #include "chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
 
 namespace chromeos {
-namespace diagnostics_service_converters {
+namespace converters {
 
 namespace unchecked {
 
@@ -168,5 +169,5 @@
   return output;
 }
 
-}  // namespace diagnostics_service_converters
+}  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
index b1f9307..1e49b3e1 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters.h
@@ -14,11 +14,11 @@
 #include <vector>
 
 #include "chromeos/components/telemetry_extension_ui/mojom/diagnostics_service.mojom-forward.h"
-#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom-forward.h"
+#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_diagnostics.mojom.h"
 #include "mojo/public/cpp/system/handle.h"
 
 namespace chromeos {
-namespace diagnostics_service_converters {
+namespace converters {
 
 // This file contains helper functions used by DiagnosticsService to convert its
 // types to/from cros_healthd DiagnosticsService types.
@@ -53,13 +53,7 @@
 
 std::string Convert(mojo::ScopedHandle handle);
 
-template <class InputT>
-auto ConvertPtr(InputT input) {
-  return (!input.is_null()) ? unchecked::UncheckedConvertPtr(std::move(input))
-                            : nullptr;
-}
-
-}  // namespace diagnostics_service_converters
+}  // namespace converters
 }  // namespace chromeos
 
 #endif  // CHROMEOS_COMPONENTS_TELEMETRY_EXTENSION_UI_DIAGNOSTICS_SERVICE_CONVERTERS_H_
diff --git a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
index 4f43f49f..11ff3bda 100644
--- a/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
+++ b/chromeos/components/telemetry_extension_ui/diagnostics_service_converters_unittest.cc
@@ -9,7 +9,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
-namespace diagnostics_service_converters {
+namespace converters {
 
 TEST(DiagnosticsServiceConvertersTest, ConvertDiagnosticRoutineStatusEnum) {
   namespace cros_healthd = ::chromeos::cros_healthd::mojom;
@@ -66,5 +66,5 @@
             cros_healthd::DiagnosticRoutineCommandEnum::kRemove);
 }
 
-}  // namespace diagnostics_service_converters
+}  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/probe_service.cc b/chromeos/components/telemetry_extension_ui/probe_service.cc
index b84d55c..03f29d2c 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service.cc
+++ b/chromeos/components/telemetry_extension_ui/probe_service.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
 #include "chromeos/components/telemetry_extension_ui/probe_service_converters.h"
 #include "chromeos/services/cros_healthd/public/cpp/service_connection.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
@@ -23,12 +24,11 @@
     const std::vector<health::mojom::ProbeCategoryEnum>& categories,
     ProbeTelemetryInfoCallback callback) {
   GetService()->ProbeTelemetryInfo(
-      probe_service_converters::ConvertCategoryVector(categories),
+      converters::ConvertCategoryVector(categories),
       base::BindOnce(
           [](health::mojom::ProbeService::ProbeTelemetryInfoCallback callback,
              cros_healthd::mojom::TelemetryInfoPtr ptr) {
-            std::move(callback).Run(
-                probe_service_converters::ConvertPtr(std::move(ptr)));
+            std::move(callback).Run(converters::ConvertPtr(std::move(ptr)));
           },
           std::move(callback)));
 }
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters.cc b/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
index 3a7222d..13bda94 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters.cc
@@ -9,11 +9,12 @@
 
 #include "base/notreached.h"
 #include "base/strings/string_number_conversions.h"
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
 #include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
 
 namespace chromeos {
-namespace probe_service_converters {
+namespace converters {
 
 namespace {
 
@@ -386,5 +387,5 @@
   return output;
 }
 
-}  // namespace probe_service_converters
+}  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters.h b/chromeos/components/telemetry_extension_ui/probe_service_converters.h
index dbc68967..f4d4ea045 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters.h
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters.h
@@ -14,10 +14,10 @@
 
 #include "base/check.h"
 #include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom-forward.h"
-#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom-forward.h"
+#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
 
 namespace chromeos {
-namespace probe_service_converters {
+namespace converters {
 
 // This file contains helper functions used by ProbeService to convert its
 // types to/from cros_healthd ProbeService types.
@@ -127,12 +127,6 @@
 
 health::mojom::UInt64ValuePtr Convert(uint64_t input);
 
-template <class InputT>
-auto ConvertPtr(InputT input) {
-  return (!input.is_null()) ? unchecked::UncheckedConvertPtr(std::move(input))
-                            : nullptr;
-}
-
 template <class OutputT, class InputT>
 std::vector<OutputT> ConvertPtrVector(std::vector<InputT> input) {
   std::vector<OutputT> output;
@@ -146,7 +140,7 @@
 std::vector<cros_healthd::mojom::ProbeCategoryEnum> ConvertCategoryVector(
     const std::vector<health::mojom::ProbeCategoryEnum>& input);
 
-}  // namespace probe_service_converters
+}  // namespace converters
 }  // namespace chromeos
 
 #endif  // CHROMEOS_COMPONENTS_TELEMETRY_EXTENSION_UI_PROBE_SERVICE_CONVERTERS_H_
diff --git a/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc b/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
index 66bf3f0..5499510c 100644
--- a/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
+++ b/chromeos/components/telemetry_extension_ui/probe_service_converters_unittest.cc
@@ -7,6 +7,7 @@
 #include <cstdint>
 #include <vector>
 
+#include "chromeos/components/telemetry_extension_ui/convert_ptr.h"
 #include "chromeos/components/telemetry_extension_ui/mojom/probe_service.mojom.h"
 #include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -15,7 +16,7 @@
 using testing::ElementsAre;
 
 namespace chromeos {
-namespace probe_service_converters {
+namespace converters {
 
 // Note: in some tests we intentionally use New() with no arguments for
 // cros_healthd::mojom types, because there can be some fields that we don't
@@ -50,12 +51,6 @@
           cros_healthd::mojom::ProbeCategoryEnum::kBluetooth));
 }
 
-// Tests that |ConvertPtr| function returns nullptr if input is nullptr.
-// ConvertPtr is a template, so we can test this function with any valid type.
-TEST(ProbeServiceConvertors, ConvertPtrTakesNullPtr) {
-  EXPECT_TRUE(ConvertPtr(cros_healthd::mojom::ProbeErrorPtr()).is_null());
-}
-
 TEST(ProbeServiceConvertors, ErrorType) {
   EXPECT_EQ(Convert(cros_healthd::mojom::ErrorType::kFileReadError),
             health::mojom::ErrorType::kFileReadError);
@@ -698,5 +693,5 @@
                 health::mojom::BluetoothResultPtr(nullptr)));
 }
 
-}  // namespace probe_service_converters
+}  // namespace converters
 }  // namespace chromeos
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt
index 7f6772c..53b71fc 100644
--- a/chromeos/profiles/airmont.afdo.newest.txt
+++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-airmont-86-4183.74-1598264968-benchmark-86.0.4240.6-r1-redacted.afdo.xz
+chromeos-chrome-amd64-airmont-86-4183.74-1598264968-benchmark-86.0.4240.8-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/broadwell.afdo.newest.txt b/chromeos/profiles/broadwell.afdo.newest.txt
index ff69a588..3a7f4959 100644
--- a/chromeos/profiles/broadwell.afdo.newest.txt
+++ b/chromeos/profiles/broadwell.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-broadwell-86-4183.59-1598262024-benchmark-86.0.4240.6-r1-redacted.afdo.xz
+chromeos-chrome-amd64-broadwell-86-4183.59-1598262024-benchmark-86.0.4240.8-r1-redacted.afdo.xz
diff --git a/chromeos/profiles/silvermont.afdo.newest.txt b/chromeos/profiles/silvermont.afdo.newest.txt
index 193c53ea..eb53f0b 100644
--- a/chromeos/profiles/silvermont.afdo.newest.txt
+++ b/chromeos/profiles/silvermont.afdo.newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-silvermont-86-4183.74-1598267562-benchmark-86.0.4240.6-r1-redacted.afdo.xz
+chromeos-chrome-amd64-silvermont-86-4183.74-1598267562-benchmark-86.0.4240.8-r1-redacted.afdo.xz
diff --git a/chromeos/services/device_sync/cryptauth_api_call_flow.cc b/chromeos/services/device_sync/cryptauth_api_call_flow.cc
index ba6037f..3e8fa5e 100644
--- a/chromeos/services/device_sync/cryptauth_api_call_flow.cc
+++ b/chromeos/services/device_sync/cryptauth_api_call_flow.cc
@@ -50,12 +50,12 @@
     const std::string& serialized_request,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& access_token,
-    const ResultCallback& result_callback,
-    const ErrorCallback& error_callback) {
+    ResultCallback result_callback,
+    ErrorCallback error_callback) {
   request_url_ = request_url;
   serialized_request_ = serialized_request;
-  result_callback_ = result_callback;
-  error_callback_ = error_callback;
+  result_callback_ = std::move(result_callback);
+  error_callback_ = std::move(error_callback);
   OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
 }
 
@@ -65,12 +65,12 @@
         request_as_query_parameters,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& access_token,
-    const ResultCallback& result_callback,
-    const ErrorCallback& error_callback) {
+    ResultCallback result_callback,
+    ErrorCallback error_callback) {
   request_url_ = request_url;
   request_as_query_parameters_ = request_as_query_parameters;
-  result_callback_ = result_callback;
-  error_callback_ = error_callback;
+  result_callback_ = std::move(result_callback);
+  error_callback_ = std::move(error_callback);
   OAuth2ApiCallFlow::Start(std::move(url_loader_factory), access_token);
 }
 
@@ -119,10 +119,10 @@
     const network::mojom::URLResponseHead* head,
     std::unique_ptr<std::string> body) {
   if (!body) {
-    error_callback_.Run(NetworkRequestError::kResponseMalformed);
+    std::move(error_callback_).Run(NetworkRequestError::kResponseMalformed);
     return;
   }
-  result_callback_.Run(std::move(*body));
+  std::move(result_callback_).Run(std::move(*body));
 }
 
 void CryptAuthApiCallFlow::ProcessApiCallFailure(
@@ -145,7 +145,7 @@
   if (body)
     PA_LOG(VERBOSE) << "API failure response body:\n" << *body;
 
-  error_callback_.Run(*error);
+  std::move(error_callback_).Run(*error);
 }
 
 net::PartialNetworkTrafficAnnotationTag
diff --git a/chromeos/services/device_sync/cryptauth_api_call_flow.h b/chromeos/services/device_sync/cryptauth_api_call_flow.h
index c9df3c7b..6a59d663 100644
--- a/chromeos/services/device_sync/cryptauth_api_call_flow.h
+++ b/chromeos/services/device_sync/cryptauth_api_call_flow.h
@@ -30,9 +30,9 @@
 
 class CryptAuthApiCallFlow : public OAuth2ApiCallFlow {
  public:
-  typedef base::Callback<void(const std::string& serialized_response)>
+  typedef base::OnceCallback<void(const std::string& serialized_response)>
       ResultCallback;
-  typedef base::Callback<void(NetworkRequestError error)> ErrorCallback;
+  typedef base::OnceCallback<void(NetworkRequestError error)> ErrorCallback;
 
   CryptAuthApiCallFlow();
   ~CryptAuthApiCallFlow() override;
@@ -49,8 +49,8 @@
       const std::string& serialized_request,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& access_token,
-      const ResultCallback& result_callback,
-      const ErrorCallback& error_callback);
+      ResultCallback result_callback,
+      ErrorCallback error_callback);
 
   // Starts the API GET request call.
   //   |request_url|: The URL endpoint of the API request.
@@ -67,8 +67,8 @@
           request_as_query_parameters,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& access_token,
-      const ResultCallback& result_callback,
-      const ErrorCallback& error_callback);
+      ResultCallback result_callback,
+      ErrorCallback error_callback);
 
   void SetPartialNetworkTrafficAnnotation(
       const net::PartialNetworkTrafficAnnotationTag&
diff --git a/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc b/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
index 6c75d97..a41eb29 100644
--- a/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
@@ -94,10 +94,10 @@
       const std::string& serialized_request) {
     flow_.StartPostRequest(
         GURL(kRequestUrl), serialized_request, shared_factory_, kAccessToken,
-        base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnResult,
-                   base::Unretained(this)),
-        base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnError,
-                   base::Unretained(this)));
+        base::BindOnce(&DeviceSyncCryptAuthApiCallFlowTest::OnResult,
+                       base::Unretained(this)),
+        base::BindOnce(&DeviceSyncCryptAuthApiCallFlowTest::OnError,
+                       base::Unretained(this)));
     // A pending fetch for the API request should be created.
     CheckCryptAuthHttpPostRequest(serialized_request);
   }
@@ -113,10 +113,10 @@
     flow_.StartGetRequest(
         GURL(kRequestUrl), request_as_query_parameters, shared_factory_,
         kAccessToken,
-        base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnResult,
-                   base::Unretained(this)),
-        base::Bind(&DeviceSyncCryptAuthApiCallFlowTest::OnError,
-                   base::Unretained(this)));
+        base::BindOnce(&DeviceSyncCryptAuthApiCallFlowTest::OnResult,
+                       base::Unretained(this)),
+        base::BindOnce(&DeviceSyncCryptAuthApiCallFlowTest::OnError,
+                       base::Unretained(this)));
     // A pending fetch for the API request should be created.
     CheckCryptAuthHttpGetRequest(request_as_query_parameters);
   }
diff --git a/chromeos/services/device_sync/cryptauth_client.h b/chromeos/services/device_sync/cryptauth_client.h
index ca4e1e9..e39177a5 100644
--- a/chromeos/services/device_sync/cryptauth_client.h
+++ b/chromeos/services/device_sync/cryptauth_client.h
@@ -63,134 +63,136 @@
 // chromeos/services/device_sync/proto/cryptauth_devicesync.proto.
 class CryptAuthClient {
  public:
-  typedef base::Callback<void(NetworkRequestError)> ErrorCallback;
+  typedef base::OnceCallback<void(NetworkRequestError)> ErrorCallback;
 
   virtual ~CryptAuthClient() {}
 
   // DeviceSync v1: GetMyDevices
-  typedef base::Callback<void(const cryptauth::GetMyDevicesResponse&)>
+  typedef base::OnceCallback<void(const cryptauth::GetMyDevicesResponse&)>
       GetMyDevicesCallback;
   virtual void GetMyDevices(const cryptauth::GetMyDevicesRequest& request,
-                            const GetMyDevicesCallback& callback,
-                            const ErrorCallback& error_callback,
+                            GetMyDevicesCallback callback,
+                            ErrorCallback error_callback,
                             const net::PartialNetworkTrafficAnnotationTag&
                                 partial_traffic_annotation) = 0;
 
   // DeviceSync v1: FindEligibleUnlockDevices
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauth::FindEligibleUnlockDevicesResponse&)>
       FindEligibleUnlockDevicesCallback;
   virtual void FindEligibleUnlockDevices(
       const cryptauth::FindEligibleUnlockDevicesRequest& request,
-      const FindEligibleUnlockDevicesCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      FindEligibleUnlockDevicesCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v1: FindEligibleForPromotion
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauth::FindEligibleForPromotionResponse&)>
       FindEligibleForPromotionCallback;
   virtual void FindEligibleForPromotion(
       const cryptauth::FindEligibleForPromotionRequest& request,
-      const FindEligibleForPromotionCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      FindEligibleForPromotionCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v1: SendDeviceSyncTickle
-  typedef base::Callback<void(const cryptauth::SendDeviceSyncTickleResponse&)>
+  typedef base::OnceCallback<void(
+      const cryptauth::SendDeviceSyncTickleResponse&)>
       SendDeviceSyncTickleCallback;
   virtual void SendDeviceSyncTickle(
       const cryptauth::SendDeviceSyncTickleRequest& request,
-      const SendDeviceSyncTickleCallback& callback,
-      const ErrorCallback& error_callback,
+      SendDeviceSyncTickleCallback callback,
+      ErrorCallback error_callback,
       const net::PartialNetworkTrafficAnnotationTag&
           partial_traffic_annotation) = 0;
 
   // DeviceSync v1: ToggleEasyUnlock
-  typedef base::Callback<void(const cryptauth::ToggleEasyUnlockResponse&)>
+  typedef base::OnceCallback<void(const cryptauth::ToggleEasyUnlockResponse&)>
       ToggleEasyUnlockCallback;
   virtual void ToggleEasyUnlock(
       const cryptauth::ToggleEasyUnlockRequest& request,
-      const ToggleEasyUnlockCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      ToggleEasyUnlockCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // Enrollment v1: SetupEnrollment
-  typedef base::Callback<void(const cryptauth::SetupEnrollmentResponse&)>
+  typedef base::OnceCallback<void(const cryptauth::SetupEnrollmentResponse&)>
       SetupEnrollmentCallback;
   virtual void SetupEnrollment(const cryptauth::SetupEnrollmentRequest& request,
-                               const SetupEnrollmentCallback& callback,
-                               const ErrorCallback& error_callback) = 0;
+                               SetupEnrollmentCallback callback,
+                               ErrorCallback error_callback) = 0;
 
   // Enrollment v1: FinishEnrollment
-  typedef base::Callback<void(const cryptauth::FinishEnrollmentResponse&)>
+  typedef base::OnceCallback<void(const cryptauth::FinishEnrollmentResponse&)>
       FinishEnrollmentCallback;
   virtual void FinishEnrollment(
       const cryptauth::FinishEnrollmentRequest& request,
-      const FinishEnrollmentCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      FinishEnrollmentCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // Enrollment v2: SyncKeys
-  typedef base::Callback<void(const cryptauthv2::SyncKeysResponse&)>
+  typedef base::OnceCallback<void(const cryptauthv2::SyncKeysResponse&)>
       SyncKeysCallback;
   virtual void SyncKeys(const cryptauthv2::SyncKeysRequest& request,
-                        const SyncKeysCallback& callback,
-                        const ErrorCallback& error_callback) = 0;
+                        SyncKeysCallback callback,
+                        ErrorCallback error_callback) = 0;
 
   // Enrollment v2: EnrollKeys
-  typedef base::Callback<void(const cryptauthv2::EnrollKeysResponse&)>
+  typedef base::OnceCallback<void(const cryptauthv2::EnrollKeysResponse&)>
       EnrollKeysCallback;
   virtual void EnrollKeys(const cryptauthv2::EnrollKeysRequest& request,
-                          const EnrollKeysCallback& callback,
-                          const ErrorCallback& error_callback) = 0;
+                          EnrollKeysCallback callback,
+                          ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: SyncMetadata
-  typedef base::Callback<void(const cryptauthv2::SyncMetadataResponse&)>
+  typedef base::OnceCallback<void(const cryptauthv2::SyncMetadataResponse&)>
       SyncMetadataCallback;
   virtual void SyncMetadata(const cryptauthv2::SyncMetadataRequest& request,
-                            const SyncMetadataCallback& callback,
-                            const ErrorCallback& error_callback) = 0;
+                            SyncMetadataCallback callback,
+                            ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: ShareGroupPrivateKey
-  typedef base::Callback<void(const cryptauthv2::ShareGroupPrivateKeyResponse&)>
+  typedef base::OnceCallback<void(
+      const cryptauthv2::ShareGroupPrivateKeyResponse&)>
       ShareGroupPrivateKeyCallback;
   virtual void ShareGroupPrivateKey(
       const cryptauthv2::ShareGroupPrivateKeyRequest& request,
-      const ShareGroupPrivateKeyCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      ShareGroupPrivateKeyCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: BatchNotifyGroupDevices
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauthv2::BatchNotifyGroupDevicesResponse&)>
       BatchNotifyGroupDevicesCallback;
   virtual void BatchNotifyGroupDevices(
       const cryptauthv2::BatchNotifyGroupDevicesRequest& request,
-      const BatchNotifyGroupDevicesCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      BatchNotifyGroupDevicesCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: BatchGetFeatureStatuses
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauthv2::BatchGetFeatureStatusesResponse&)>
       BatchGetFeatureStatusesCallback;
   virtual void BatchGetFeatureStatuses(
       const cryptauthv2::BatchGetFeatureStatusesRequest& request,
-      const BatchGetFeatureStatusesCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      BatchGetFeatureStatusesCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: BatchSetFeatureStatuses
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauthv2::BatchSetFeatureStatusesResponse&)>
       BatchSetFeatureStatusesCallback;
   virtual void BatchSetFeatureStatuses(
       const cryptauthv2::BatchSetFeatureStatusesRequest& request,
-      const BatchSetFeatureStatusesCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      BatchSetFeatureStatusesCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // DeviceSync v2: GetDevicesActivityStatus
-  typedef base::Callback<void(
+  typedef base::OnceCallback<void(
       const cryptauthv2::GetDevicesActivityStatusResponse&)>
       GetDevicesActivityStatusCallback;
   virtual void GetDevicesActivityStatus(
       const cryptauthv2::GetDevicesActivityStatusRequest& request,
-      const GetDevicesActivityStatusCallback& callback,
-      const ErrorCallback& error_callback) = 0;
+      GetDevicesActivityStatusCallback callback,
+      ErrorCallback error_callback) = 0;
 
   // Returns the access token used to make the request. If no request has been
   // made yet, this function will return an empty string.
diff --git a/chromeos/services/device_sync/cryptauth_client_impl.cc b/chromeos/services/device_sync/cryptauth_client_impl.cc
index 47b0b03..91d66fb6 100644
--- a/chromeos/services/device_sync/cryptauth_client_impl.cc
+++ b/chromeos/services/device_sync/cryptauth_client_impl.cc
@@ -123,19 +123,20 @@
 
 void CryptAuthClientImpl::GetMyDevices(
     const cryptauth::GetMyDevicesRequest& request,
-    const GetMyDevicesCallback& callback,
-    const ErrorCallback& error_callback,
+    GetMyDevicesCallback callback,
+    ErrorCallback error_callback,
     const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
   MakeApiCall(CreateV1RequestUrl(kGetMyDevicesPath), RequestType::kPost,
               RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::FindEligibleUnlockDevices(
     const cryptauth::FindEligibleUnlockDevicesRequest& request,
-    const FindEligibleUnlockDevicesCallback& callback,
-    const ErrorCallback& error_callback) {
+    FindEligibleUnlockDevicesCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_find_eligible_unlock_devices", "oauth2_api_call_flow",
@@ -161,17 +162,17 @@
           }
         }
       })");
-  MakeApiCall(CreateV1RequestUrl(kFindEligibleUnlockDevicesPath),
-              RequestType::kPost,
-              RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+  MakeApiCall(
+      CreateV1RequestUrl(kFindEligibleUnlockDevicesPath), RequestType::kPost,
+      RequestWithDeviceClassifierSet(request).SerializeAsString(),
+      base::nullopt /* request_as_query_parameters */, std::move(callback),
+      std::move(error_callback), partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::FindEligibleForPromotion(
     const cryptauth::FindEligibleForPromotionRequest& request,
-    const FindEligibleForPromotionCallback& callback,
-    const ErrorCallback& error_callback) {
+    FindEligibleForPromotionCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_find_eligible_for_promotion", "oauth2_api_call_flow",
@@ -194,28 +195,29 @@
           }
         }
       })");
-  MakeApiCall(CreateV1RequestUrl(kFindEligibleForPromotionPath),
-              RequestType::kPost,
-              RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+  MakeApiCall(
+      CreateV1RequestUrl(kFindEligibleForPromotionPath), RequestType::kPost,
+      RequestWithDeviceClassifierSet(request).SerializeAsString(),
+      base::nullopt /* request_as_query_parameters */, std::move(callback),
+      std::move(error_callback), partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::SendDeviceSyncTickle(
     const cryptauth::SendDeviceSyncTickleRequest& request,
-    const SendDeviceSyncTickleCallback& callback,
-    const ErrorCallback& error_callback,
+    SendDeviceSyncTickleCallback callback,
+    ErrorCallback error_callback,
     const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
   MakeApiCall(CreateV1RequestUrl(kSendDeviceSyncTicklePath), RequestType::kPost,
               RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::ToggleEasyUnlock(
     const cryptauth::ToggleEasyUnlockRequest& request,
-    const ToggleEasyUnlockCallback& callback,
-    const ErrorCallback& error_callback) {
+    ToggleEasyUnlockCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation("cryptauth_toggle_easyunlock",
                                                  "oauth2_api_call_flow", R"(
@@ -241,14 +243,15 @@
       })");
   MakeApiCall(CreateV1RequestUrl(kToggleEasyUnlockPath), RequestType::kPost,
               RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::SetupEnrollment(
     const cryptauth::SetupEnrollmentRequest& request,
-    const SetupEnrollmentCallback& callback,
-    const ErrorCallback& error_callback) {
+    SetupEnrollmentCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_enrollment_flow_setup", "oauth2_api_call_flow", R"(
@@ -277,14 +280,15 @@
       })");
   MakeApiCall(CreateV1RequestUrl(kSetupEnrollmentPath), RequestType::kPost,
               RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::FinishEnrollment(
     const cryptauth::FinishEnrollmentRequest& request,
-    const FinishEnrollmentCallback& callback,
-    const ErrorCallback& error_callback) {
+    FinishEnrollmentCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_enrollment_flow_finish", "oauth2_api_call_flow", R"(
@@ -310,13 +314,14 @@
       })");
   MakeApiCall(CreateV1RequestUrl(kFinishEnrollmentPath), RequestType::kPost,
               RequestWithDeviceClassifierSet(request).SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::SyncKeys(const cryptauthv2::SyncKeysRequest& request,
-                                   const SyncKeysCallback& callback,
-                                   const ErrorCallback& error_callback) {
+                                   SyncKeysCallback callback,
+                                   ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_enrollment_flow_sync_keys", "oauth2_api_call_flow", R"(
@@ -346,14 +351,15 @@
       })");
   MakeApiCall(CreateV2EnrollmentRequestUrl(kSyncKeysPath), RequestType::kPost,
               request.SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::EnrollKeys(
     const cryptauthv2::EnrollKeysRequest& request,
-    const EnrollKeysCallback& callback,
-    const ErrorCallback& error_callback) {
+    EnrollKeysCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_enrollment_flow_enroll_keys", "oauth2_api_call_flow",
@@ -382,14 +388,15 @@
       })");
   MakeApiCall(CreateV2EnrollmentRequestUrl(kEnrollKeysPath), RequestType::kPost,
               request.SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::SyncMetadata(
     const cryptauthv2::SyncMetadataRequest& request,
-    const SyncMetadataCallback& callback,
-    const ErrorCallback& error_callback) {
+    SyncMetadataCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_sync_metadata", "oauth2_api_call_flow",
@@ -423,14 +430,15 @@
       })");
   MakeApiCall(CreateV2DeviceSyncRequestUrl(kSyncMetadataPath),
               RequestType::kPost, request.SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::ShareGroupPrivateKey(
     const cryptauthv2::ShareGroupPrivateKeyRequest& request,
-    const ShareGroupPrivateKeyCallback& callback,
-    const ErrorCallback& error_callback) {
+    ShareGroupPrivateKeyCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_share_group_private_key",
@@ -462,14 +470,15 @@
       })");
   MakeApiCall(CreateV2DeviceSyncRequestUrl(kShareGroupPrivateKeyPath),
               RequestType::kPost, request.SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::BatchNotifyGroupDevices(
     const cryptauthv2::BatchNotifyGroupDevicesRequest& request,
-    const BatchNotifyGroupDevicesCallback& callback,
-    const ErrorCallback& error_callback) {
+    BatchNotifyGroupDevicesCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_batch_notify_group_devices",
@@ -505,13 +514,14 @@
       CreateV2DeviceSyncRequestUrl(kBatchNotifyGroupDevicesPath),
       RequestType::kGet, base::nullopt /* serialized_request */,
       cryptauthv2::BatchNotifyGroupDevicesRequestToQueryParameters(request),
-      callback, error_callback, partial_traffic_annotation);
+      std::move(callback), std::move(error_callback),
+      partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::BatchGetFeatureStatuses(
     const cryptauthv2::BatchGetFeatureStatusesRequest& request,
-    const BatchGetFeatureStatusesCallback& callback,
-    const ErrorCallback& error_callback) {
+    BatchGetFeatureStatusesCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_batch_get_feature_statuses",
@@ -542,13 +552,14 @@
       CreateV2DeviceSyncRequestUrl(kBatchGetFeatureStatusesPath),
       RequestType::kGet, base::nullopt /* serialized_request */,
       cryptauthv2::BatchGetFeatureStatusesRequestToQueryParameters(request),
-      callback, error_callback, partial_traffic_annotation);
+      std::move(callback), std::move(error_callback),
+      partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::BatchSetFeatureStatuses(
     const cryptauthv2::BatchSetFeatureStatusesRequest& request,
-    const BatchSetFeatureStatusesCallback& callback,
-    const ErrorCallback& error_callback) {
+    BatchSetFeatureStatusesCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_batch_set_feature_statuses",
@@ -579,14 +590,15 @@
       })");
   MakeApiCall(CreateV2DeviceSyncRequestUrl(kBatchSetFeatureStatusesPath),
               RequestType::kPost, request.SerializeAsString(),
-              base::nullopt /* request_as_query_parameters */, callback,
-              error_callback, partial_traffic_annotation);
+              base::nullopt /* request_as_query_parameters */,
+              std::move(callback), std::move(error_callback),
+              partial_traffic_annotation);
 }
 
 void CryptAuthClientImpl::GetDevicesActivityStatus(
     const cryptauthv2::GetDevicesActivityStatusRequest& request,
-    const GetDevicesActivityStatusCallback& callback,
-    const ErrorCallback& error_callback) {
+    GetDevicesActivityStatusCallback callback,
+    ErrorCallback error_callback) {
   net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
       net::DefinePartialNetworkTrafficAnnotation(
           "cryptauth_v2_devicesync_get_devices_activity_status",
@@ -619,7 +631,8 @@
       CreateV2DeviceSyncRequestUrl(kGetDevicesActivityStatusPath),
       RequestType::kGet, base::nullopt /* serialized_request */,
       cryptauthv2::GetDevicesActivityStatusRequestToQueryParameters(request),
-      callback, error_callback, partial_traffic_annotation);
+      std::move(callback), std::move(error_callback),
+      partial_traffic_annotation);
 }
 
 std::string CryptAuthClientImpl::GetAccessTokenUsed() {
@@ -633,8 +646,8 @@
     const base::Optional<std::string>& serialized_request,
     const base::Optional<std::vector<std::pair<std::string, std::string>>>&
         request_as_query_parameters,
-    const base::Callback<void(const ResponseProto&)>& response_callback,
-    const ErrorCallback& error_callback,
+    base::OnceCallback<void(const ResponseProto&)> response_callback,
+    ErrorCallback error_callback,
     const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation) {
   if (has_call_started_) {
     PA_LOG(ERROR) << "CryptAuthClientImpl::MakeApiCall(): Tried to make an API "
@@ -648,7 +661,7 @@
       partial_traffic_annotation);
 
   request_url_ = request_url;
-  error_callback_ = error_callback;
+  error_callback_ = std::move(error_callback);
 
   OAuth2AccessTokenManager::ScopeSet scopes;
   scopes.insert(kCryptAuthOAuth2Scope);
@@ -659,7 +672,7 @@
           base::BindOnce(
               &CryptAuthClientImpl::OnAccessTokenFetched<ResponseProto>,
               weak_ptr_factory_.GetWeakPtr(), request_type, serialized_request,
-              request_as_query_parameters, response_callback),
+              request_as_query_parameters, std::move(response_callback)),
           signin::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable,
           signin::ConsentLevel::kNotRequired);
 }
@@ -670,7 +683,7 @@
     const base::Optional<std::string>& serialized_request,
     const base::Optional<std::vector<std::pair<std::string, std::string>>>&
         request_as_query_parameters,
-    const base::Callback<void(const ResponseProto&)>& response_callback,
+    base::OnceCallback<void(const ResponseProto&)> response_callback,
     GoogleServiceAuthError error,
     signin::AccessTokenInfo access_token_info) {
   access_token_fetcher_.reset();
@@ -687,38 +700,40 @@
       api_call_flow_->StartGetRequest(
           request_url_, *request_as_query_parameters, url_loader_factory_,
           access_token_used_,
-          base::Bind(&CryptAuthClientImpl::OnFlowSuccess<ResponseProto>,
-                     weak_ptr_factory_.GetWeakPtr(), response_callback),
-          base::Bind(&CryptAuthClientImpl::OnApiCallFailed,
-                     weak_ptr_factory_.GetWeakPtr()));
+          base::BindOnce(&CryptAuthClientImpl::OnFlowSuccess<ResponseProto>,
+                         weak_ptr_factory_.GetWeakPtr(),
+                         std::move(response_callback)),
+          base::BindOnce(&CryptAuthClientImpl::OnApiCallFailed,
+                         weak_ptr_factory_.GetWeakPtr()));
       break;
     case RequestType::kPost:
       DCHECK(serialized_request && !request_as_query_parameters);
       api_call_flow_->StartPostRequest(
           request_url_, *serialized_request, url_loader_factory_,
           access_token_used_,
-          base::Bind(&CryptAuthClientImpl::OnFlowSuccess<ResponseProto>,
-                     weak_ptr_factory_.GetWeakPtr(), response_callback),
-          base::Bind(&CryptAuthClientImpl::OnApiCallFailed,
-                     weak_ptr_factory_.GetWeakPtr()));
+          base::BindOnce(&CryptAuthClientImpl::OnFlowSuccess<ResponseProto>,
+                         weak_ptr_factory_.GetWeakPtr(),
+                         std::move(response_callback)),
+          base::BindOnce(&CryptAuthClientImpl::OnApiCallFailed,
+                         weak_ptr_factory_.GetWeakPtr()));
       break;
   }
 }
 
 template <class ResponseProto>
 void CryptAuthClientImpl::OnFlowSuccess(
-    const base::Callback<void(const ResponseProto&)>& result_callback,
+    base::OnceCallback<void(const ResponseProto&)> result_callback,
     const std::string& serialized_response) {
   ResponseProto response;
   if (!response.ParseFromString(serialized_response)) {
     OnApiCallFailed(NetworkRequestError::kResponseMalformed);
     return;
   }
-  result_callback.Run(response);
+  std::move(result_callback).Run(response);
 }
 
 void CryptAuthClientImpl::OnApiCallFailed(NetworkRequestError error) {
-  error_callback_.Run(error);
+  std::move(error_callback_).Run(error);
 }
 
 template <class RequestProto>
diff --git a/chromeos/services/device_sync/cryptauth_client_impl.h b/chromeos/services/device_sync/cryptauth_client_impl.h
index f14799c8..4424741 100644
--- a/chromeos/services/device_sync/cryptauth_client_impl.h
+++ b/chromeos/services/device_sync/cryptauth_client_impl.h
@@ -52,62 +52,62 @@
 
   // CryptAuthClient:
   void GetMyDevices(const cryptauth::GetMyDevicesRequest& request,
-                    const GetMyDevicesCallback& callback,
-                    const ErrorCallback& error_callback,
+                    GetMyDevicesCallback callback,
+                    ErrorCallback error_callback,
                     const net::PartialNetworkTrafficAnnotationTag&
                         partial_traffic_annotation) override;
   void FindEligibleUnlockDevices(
       const cryptauth::FindEligibleUnlockDevicesRequest& request,
-      const FindEligibleUnlockDevicesCallback& callback,
-      const ErrorCallback& error_callback) override;
+      FindEligibleUnlockDevicesCallback callback,
+      ErrorCallback error_callback) override;
   void FindEligibleForPromotion(
       const cryptauth::FindEligibleForPromotionRequest& request,
-      const FindEligibleForPromotionCallback& callback,
-      const ErrorCallback& error_callback) override;
+      FindEligibleForPromotionCallback callback,
+      ErrorCallback error_callback) override;
   void SendDeviceSyncTickle(
       const cryptauth::SendDeviceSyncTickleRequest& request,
-      const SendDeviceSyncTickleCallback& callback,
-      const ErrorCallback& error_callback,
+      SendDeviceSyncTickleCallback callback,
+      ErrorCallback error_callback,
       const net::PartialNetworkTrafficAnnotationTag& partial_traffic_annotation)
       override;
   void ToggleEasyUnlock(const cryptauth::ToggleEasyUnlockRequest& request,
-                        const ToggleEasyUnlockCallback& callback,
-                        const ErrorCallback& error_callback) override;
+                        ToggleEasyUnlockCallback callback,
+                        ErrorCallback error_callback) override;
   void SetupEnrollment(const cryptauth::SetupEnrollmentRequest& request,
-                       const SetupEnrollmentCallback& callback,
-                       const ErrorCallback& error_callback) override;
+                       SetupEnrollmentCallback callback,
+                       ErrorCallback error_callback) override;
   void FinishEnrollment(const cryptauth::FinishEnrollmentRequest& request,
-                        const FinishEnrollmentCallback& callback,
-                        const ErrorCallback& error_callback) override;
+                        FinishEnrollmentCallback callback,
+                        ErrorCallback error_callback) override;
   void SyncKeys(const cryptauthv2::SyncKeysRequest& request,
-                const SyncKeysCallback& callback,
-                const ErrorCallback& error_callback) override;
+                SyncKeysCallback callback,
+                ErrorCallback error_callback) override;
   void EnrollKeys(const cryptauthv2::EnrollKeysRequest& request,
-                  const EnrollKeysCallback& callback,
-                  const ErrorCallback& error_callback) override;
+                  EnrollKeysCallback callback,
+                  ErrorCallback error_callback) override;
   void SyncMetadata(const cryptauthv2::SyncMetadataRequest& request,
-                    const SyncMetadataCallback& callback,
-                    const ErrorCallback& error_callback) override;
+                    SyncMetadataCallback callback,
+                    ErrorCallback error_callback) override;
   void ShareGroupPrivateKey(
       const cryptauthv2::ShareGroupPrivateKeyRequest& request,
-      const ShareGroupPrivateKeyCallback& callback,
-      const ErrorCallback& error_callback) override;
+      ShareGroupPrivateKeyCallback callback,
+      ErrorCallback error_callback) override;
   void BatchNotifyGroupDevices(
       const cryptauthv2::BatchNotifyGroupDevicesRequest& request,
-      const BatchNotifyGroupDevicesCallback& callback,
-      const ErrorCallback& error_callback) override;
+      BatchNotifyGroupDevicesCallback callback,
+      ErrorCallback error_callback) override;
   void BatchGetFeatureStatuses(
       const cryptauthv2::BatchGetFeatureStatusesRequest& request,
-      const BatchGetFeatureStatusesCallback& callback,
-      const ErrorCallback& error_callback) override;
+      BatchGetFeatureStatusesCallback callback,
+      ErrorCallback error_callback) override;
   void BatchSetFeatureStatuses(
       const cryptauthv2::BatchSetFeatureStatusesRequest& request,
-      const BatchSetFeatureStatusesCallback& callback,
-      const ErrorCallback& error_callback) override;
+      BatchSetFeatureStatusesCallback callback,
+      ErrorCallback error_callback) override;
   void GetDevicesActivityStatus(
       const cryptauthv2::GetDevicesActivityStatusRequest& request,
-      const GetDevicesActivityStatusCallback& callback,
-      const ErrorCallback& error_callback) override;
+      GetDevicesActivityStatusCallback callback,
+      ErrorCallback error_callback) override;
   std::string GetAccessTokenUsed() override;
 
  private:
@@ -135,8 +135,8 @@
       const base::Optional<std::string>& serialized_request,
       const base::Optional<std::vector<std::pair<std::string, std::string>>>&
           request_as_query_parameters,
-      const base::Callback<void(const ResponseProto&)>& response_callback,
-      const ErrorCallback& error_callback,
+      base::OnceCallback<void(const ResponseProto&)> response_callback,
+      ErrorCallback error_callback,
       const net::PartialNetworkTrafficAnnotationTag&
           partial_traffic_annotation);
 
@@ -147,7 +147,7 @@
       const base::Optional<std::string>& serialized_request,
       const base::Optional<std::vector<std::pair<std::string, std::string>>>&
           request_as_query_parameters,
-      const base::Callback<void(const ResponseProto&)>& response_callback,
+      base::OnceCallback<void(const ResponseProto&)> response_callback,
       GoogleServiceAuthError error,
       signin::AccessTokenInfo access_token_info);
 
@@ -155,7 +155,7 @@
   // return the result.
   template <class ResponseProto>
   void OnFlowSuccess(
-      const base::Callback<void(const ResponseProto&)>& result_callback,
+      base::OnceCallback<void(const ResponseProto&)> result_callback,
       const std::string& serialized_response);
 
   // Called when the current API call fails at any step.
diff --git a/chromeos/services/device_sync/cryptauth_client_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_client_impl_unittest.cc
index 53059012..bdbf38dc 100644
--- a/chromeos/services/device_sync/cryptauth_client_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_client_impl_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/gmock_move_support.h"
 #include "base/test/gtest_util.h"
 #include "base/test/null_task_runner.h"
 #include "base/test/task_environment.h"
@@ -79,24 +80,46 @@
   }
   virtual ~MockCryptAuthApiCallFlow() {}
 
+  void StartPostRequest(
+      const GURL& request_url,
+      const std::string& serialized_request,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& access_token,
+      ResultCallback result_callback,
+      ErrorCallback error_callback) override {
+    StartPostRequest_(request_url, serialized_request, url_loader_factory,
+                      access_token, result_callback, error_callback);
+  }
   MOCK_METHOD6(
-      StartPostRequest,
+      StartPostRequest_,
       void(const GURL& request_url,
            const std::string& serialized_request,
            scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
            const std::string& access_token,
-           const ResultCallback& result_callback,
-           const ErrorCallback& error_callback));
+           ResultCallback& result_callback,
+           ErrorCallback& error_callback));
 
+  void StartGetRequest(
+      const GURL& request_url,
+      const std::vector<std::pair<std::string, std::string>>&
+          request_as_query_parameters,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& access_token,
+      ResultCallback result_callback,
+      ErrorCallback error_callback) override {
+    StartGetRequest_(request_url, request_as_query_parameters,
+                     url_loader_factory, access_token, result_callback,
+                     error_callback);
+  }
   MOCK_METHOD6(
-      StartGetRequest,
+      StartGetRequest_,
       void(const GURL& request_url,
            const std::vector<std::pair<std::string, std::string>>&
                request_as_query_parameters,
            scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
            const std::string& access_token,
-           const ResultCallback& result_callback,
-           const ErrorCallback& error_callback));
+           ResultCallback& result_callback,
+           ErrorCallback& error_callback));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockCryptAuthApiCallFlow);
@@ -171,10 +194,10 @@
   void ExpectPostRequest(const std::string& request_url) {
     GURL url(request_url);
     EXPECT_CALL(*api_call_flow_,
-                StartPostRequest(url, _, shared_factory_, kAccessToken, _, _))
+                StartPostRequest_(url, _, shared_factory_, kAccessToken, _, _))
         .WillOnce(DoAll(SaveArg<1>(&serialized_request_),
-                        SaveArg<4>(&flow_result_callback_),
-                        SaveArg<5>(&flow_error_callback_)));
+                        MoveArg<4>(&flow_result_callback_),
+                        MoveArg<5>(&flow_error_callback_)));
   }
 
   // Sets up an expectation and captures a CryptAuth API GET request to
@@ -182,22 +205,22 @@
   void ExpectGetRequest(const std::string& request_url) {
     GURL url(request_url);
     EXPECT_CALL(*api_call_flow_,
-                StartGetRequest(url, _, shared_factory_, kAccessToken, _, _))
+                StartGetRequest_(url, _, shared_factory_, kAccessToken, _, _))
         .WillOnce(DoAll(SaveArg<1>(&request_as_query_parameters_),
-                        SaveArg<4>(&flow_result_callback_),
-                        SaveArg<5>(&flow_error_callback_)));
+                        MoveArg<4>(&flow_result_callback_),
+                        MoveArg<5>(&flow_error_callback_)));
   }
 
   // Returns |response_proto| as the result to the current API request.
   // ExpectResult() must have been called first.
   void FinishApiCallFlow(const google::protobuf::MessageLite* response_proto) {
-    flow_result_callback_.Run(response_proto->SerializeAsString());
+    std::move(flow_result_callback_).Run(response_proto->SerializeAsString());
   }
 
   // Ends the current API request with |error|. ExpectResult() must have been
   // called first.
   void FailApiCallFlow(NetworkRequestError error) {
-    flow_error_callback_.Run(error);
+    std::move(flow_error_callback_).Run(error);
   }
 
  protected:
@@ -226,9 +249,9 @@
   request_proto.set_allow_stale_read(true);
   client_->GetMyDevices(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>),
+      base::BindOnce(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -269,8 +292,8 @@
   NetworkRequestError error;
   client_->GetMyDevices(
       cryptauth::GetMyDevicesRequest(),
-      base::Bind(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
-      base::Bind(&SaveResult<NetworkRequestError>, &error),
+      base::BindOnce(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
+      base::BindOnce(&SaveResult<NetworkRequestError>, &error),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -290,10 +313,10 @@
   request_proto.set_callback_bluetooth_address(kBluetoothAddress2);
   client_->FindEligibleUnlockDevices(
       request_proto,
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauth::FindEligibleUnlockDevicesResponse>,
           &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -338,9 +361,9 @@
   request_proto.set_callback_bluetooth_address(kBluetoothAddress1);
   client_->FindEligibleUnlockDevices(
       request_proto,
-      base::Bind(
+      base::BindOnce(
           &NotCalledConstRef<cryptauth::FindEligibleUnlockDevicesResponse>),
-      base::Bind(&SaveResult<NetworkRequestError>, &error));
+      base::BindOnce(&SaveResult<NetworkRequestError>, &error));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -357,10 +380,10 @@
   cryptauth::FindEligibleForPromotionResponse result_proto;
   client_->FindEligibleForPromotion(
       cryptauth::FindEligibleForPromotionRequest(),
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauth::FindEligibleForPromotionResponse>,
           &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -380,9 +403,10 @@
   cryptauth::SendDeviceSyncTickleResponse result_proto;
   client_->SendDeviceSyncTickle(
       cryptauth::SendDeviceSyncTickleRequest(),
-      base::Bind(&SaveResultConstRef<cryptauth::SendDeviceSyncTickleResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>),
+      base::BindOnce(
+          &SaveResultConstRef<cryptauth::SendDeviceSyncTickleResponse>,
+          &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -407,9 +431,9 @@
   request_proto.set_public_key(kPublicKey1);
   client_->ToggleEasyUnlock(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::ToggleEasyUnlockResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauth::ToggleEasyUnlockResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -441,9 +465,9 @@
   request_proto.add_types("testProtocol");
   client_->SetupEnrollment(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::SetupEnrollmentResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauth::SetupEnrollmentResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -489,9 +513,9 @@
   request_proto.set_device_ephemeral_key(kDeviceEphemeralKey);
   client_->FinishEnrollment(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::FinishEnrollmentResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauth::FinishEnrollmentResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -523,9 +547,9 @@
   cryptauthv2::SyncKeysResponse result_proto;
   client_->SyncKeys(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauthv2::SyncKeysResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauthv2::SyncKeysResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -555,9 +579,9 @@
   cryptauthv2::EnrollKeysResponse result_proto;
   client_->EnrollKeys(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauthv2::EnrollKeysResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauthv2::EnrollKeysResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -599,9 +623,9 @@
   cryptauthv2::SyncMetadataResponse result;
   client_->SyncMetadata(
       request,
-      base::Bind(&SaveResultConstRef<cryptauthv2::SyncMetadataResponse>,
-                 &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&SaveResultConstRef<cryptauthv2::SyncMetadataResponse>,
+                     &result),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -665,9 +689,10 @@
   cryptauthv2::ShareGroupPrivateKeyResponse result;
   client_->ShareGroupPrivateKey(
       request,
-      base::Bind(&SaveResultConstRef<cryptauthv2::ShareGroupPrivateKeyResponse>,
-                 &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(
+          &SaveResultConstRef<cryptauthv2::ShareGroupPrivateKeyResponse>,
+          &result),
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -709,10 +734,10 @@
   cryptauthv2::BatchNotifyGroupDevicesResponse result;
   client_->BatchNotifyGroupDevices(
       request,
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauthv2::BatchNotifyGroupDevicesResponse>,
           &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -761,10 +786,10 @@
   cryptauthv2::BatchGetFeatureStatusesResponse result;
   client_->BatchGetFeatureStatuses(
       request,
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauthv2::BatchGetFeatureStatusesResponse>,
           &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -843,10 +868,10 @@
   cryptauthv2::BatchSetFeatureStatusesResponse result;
   client_->BatchSetFeatureStatuses(
       request,
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauthv2::BatchSetFeatureStatusesResponse>,
           &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -916,10 +941,10 @@
   cryptauthv2::GetDevicesActivityStatusResponse result;
   client_->GetDevicesActivityStatus(
       request,
-      base::Bind(
+      base::BindOnce(
           &SaveResultConstRef<cryptauthv2::GetDevicesActivityStatusResponse>,
           &result),
-      base::Bind(&NotCalled<NetworkRequestError>));
+      base::BindOnce(&NotCalled<NetworkRequestError>));
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
@@ -965,8 +990,8 @@
   NetworkRequestError error;
   client_->GetMyDevices(
       cryptauth::GetMyDevicesRequest(),
-      base::Bind(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
-      base::Bind(&SaveResult<NetworkRequestError>, &error),
+      base::BindOnce(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
+      base::BindOnce(&SaveResult<NetworkRequestError>, &error),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
@@ -983,14 +1008,15 @@
   NetworkRequestError error;
   client_->GetMyDevices(
       cryptauth::GetMyDevicesRequest(),
-      base::Bind(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
-      base::Bind(&SaveResult<NetworkRequestError>, &error),
+      base::BindOnce(&NotCalledConstRef<cryptauth::GetMyDevicesResponse>),
+      base::BindOnce(&SaveResult<NetworkRequestError>, &error),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
           kAccessToken, base::Time::Max());
 
-  flow_result_callback_.Run("Not a valid serialized response message.");
+  std::move(flow_result_callback_)
+      .Run("Not a valid serialized response message.");
   EXPECT_EQ(NetworkRequestError::kResponseMalformed, error);
 }
 
@@ -1004,9 +1030,9 @@
   cryptauth::GetMyDevicesResponse result_proto;
   client_->GetMyDevices(
       cryptauth::GetMyDevicesRequest(),
-      base::Bind(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>),
+      base::BindOnce(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -1017,9 +1043,9 @@
     NetworkRequestError error;
     EXPECT_DCHECK_DEATH(client_->FindEligibleUnlockDevices(
         cryptauth::FindEligibleUnlockDevicesRequest(),
-        base::Bind(
+        base::BindOnce(
             &NotCalledConstRef<cryptauth::FindEligibleUnlockDevicesResponse>),
-        base::Bind(&SaveResult<NetworkRequestError>, &error)));
+        base::BindOnce(&SaveResult<NetworkRequestError>, &error)));
   }
 
   // Complete first request.
@@ -1044,9 +1070,9 @@
     cryptauth::GetMyDevicesResponse result_proto;
     client_->GetMyDevices(
         cryptauth::GetMyDevicesRequest(),
-        base::Bind(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
-                   &result_proto),
-        base::Bind(&NotCalled<NetworkRequestError>),
+        base::BindOnce(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
+                       &result_proto),
+        base::BindOnce(&NotCalled<NetworkRequestError>),
         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
     identity_test_environment_
         .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -1065,9 +1091,9 @@
     NetworkRequestError error;
     EXPECT_DCHECK_DEATH(client_->FindEligibleUnlockDevices(
         cryptauth::FindEligibleUnlockDevicesRequest(),
-        base::Bind(
+        base::BindOnce(
             &NotCalledConstRef<cryptauth::FindEligibleUnlockDevicesResponse>),
-        base::Bind(&SaveResult<NetworkRequestError>, &error)));
+        base::BindOnce(&SaveResult<NetworkRequestError>, &error)));
   }
 }
 
@@ -1081,9 +1107,9 @@
   request_proto.set_allow_stale_read(true);
   client_->GetMyDevices(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>),
+      base::BindOnce(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
@@ -1114,9 +1140,9 @@
   request_proto.set_allow_stale_read(true);
   client_->GetMyDevices(
       request_proto,
-      base::Bind(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
-                 &result_proto),
-      base::Bind(&NotCalled<NetworkRequestError>),
+      base::BindOnce(&SaveResultConstRef<cryptauth::GetMyDevicesResponse>,
+                     &result_proto),
+      base::BindOnce(&NotCalled<NetworkRequestError>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
   identity_test_environment_
       .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
diff --git a/chromeos/services/device_sync/cryptauth_device_activity_getter_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_device_activity_getter_impl_unittest.cc
index ccf59448..3c4e909 100644
--- a/chromeos/services/device_sync/cryptauth_device_activity_getter_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_device_activity_getter_impl_unittest.cc
@@ -163,15 +163,15 @@
  private:
   void OnGetDevicesActivityStatus(
       const cryptauthv2::GetDevicesActivityStatusRequest& request,
-      const CryptAuthClient::GetDevicesActivityStatusCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::GetDevicesActivityStatusCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     EXPECT_FALSE(get_device_activity_status_request_);
     EXPECT_FALSE(get_device_activity_status_success_callback_);
     EXPECT_FALSE(get_device_activity_status_failure_callback_);
 
     get_device_activity_status_request_ = request;
-    get_device_activity_status_success_callback_ = callback;
-    get_device_activity_status_failure_callback_ = error_callback;
+    get_device_activity_status_success_callback_ = std::move(callback);
+    get_device_activity_status_failure_callback_ = std::move(error_callback);
   }
 
   void OnGetDevicesActivityStatusFinished(
diff --git a/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
index 5832552..96d6c30 100644
--- a/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_device_manager_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/gmock_move_support.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "chromeos/components/multidevice/software_feature_state.h"
@@ -587,10 +588,10 @@
 
   // MockCryptAuthClientFactory::Observer:
   void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
-    EXPECT_CALL(*client, GetMyDevices(_, _, _, _))
+    EXPECT_CALL(*client, GetMyDevices_(_, _, _, _))
         .WillOnce(DoAll(SaveArg<0>(&get_my_devices_request_),
-                        SaveArg<1>(&success_callback_),
-                        SaveArg<2>(&error_callback_)));
+                        MoveArg<1>(&success_callback_),
+                        MoveArg<2>(&error_callback_)));
   }
 
   MockSyncScheduler* sync_scheduler() {
@@ -761,7 +762,7 @@
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
 
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
   EXPECT_EQ(clock_.Now(), device_manager_->GetLastSyncTime());
 
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -780,7 +781,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
   EXPECT_EQ(clock_.Now(), device_manager_->GetLastSyncTime());
 
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -802,7 +803,7 @@
               OnSyncFinishedProxy(
                   CryptAuthDeviceManager::SyncResult::FAILURE,
                   CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED));
-  error_callback_.Run(NetworkRequestError::kEndpointNotFound);
+  std::move(error_callback_).Run(NetworkRequestError::kEndpointNotFound);
   EXPECT_EQ(old_sync_time, device_manager_->GetLastSyncTime());
   EXPECT_TRUE(pref_service_.GetBoolean(
       prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure));
@@ -817,7 +818,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
   EXPECT_EQ(clock_.Now(), device_manager_->GetLastSyncTime());
 
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -844,7 +845,7 @@
               OnSyncFinishedProxy(
                   CryptAuthDeviceManager::SyncResult::FAILURE,
                   CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED));
-  error_callback_.Run(NetworkRequestError::kAuthenticationError);
+  std::move(error_callback_).Run(NetworkRequestError::kAuthenticationError);
   EXPECT_EQ(old_sync_time, device_manager_->GetLastSyncTime());
   EXPECT_TRUE(pref_service_.GetBoolean(
       prefs::kCryptAuthDeviceSyncIsRecoveringFromFailure));
@@ -857,7 +858,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
   EXPECT_EQ(clock_.Now(), device_manager_->GetLastSyncTime());
 
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -890,7 +891,7 @@
   synced_device.set_unlockable(kStoredUnlockable);
   cryptauth::GetMyDevicesResponse get_my_devices_response;
   get_my_devices_response.add_devices()->CopyFrom(synced_device);
-  success_callback_.Run(get_my_devices_response);
+  std::move(success_callback_).Run(get_my_devices_response);
 
   // Check that devices are still the same after sync.
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -908,7 +909,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(empty_response);
+  std::move(success_callback_).Run(empty_response);
 
   ExpectSyncedDevicesAndPrefAreEqual(
       std::vector<cryptauth::ExternalDeviceInfo>(),
@@ -944,7 +945,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(response);
+  std::move(success_callback_).Run(response);
 
   ExpectSyncedDevicesAndPrefAreEqual(
       expected_devices, device_manager_->GetSyncedDevices(), pref_service_);
@@ -962,7 +963,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   ExpectSyncedDevicesAndPrefAreEqual(
       devices_in_response_, device_manager_->GetSyncedDevices(), pref_service_);
@@ -980,7 +981,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   ExpectSyncedDevicesAndPrefAreEqual(
       devices_in_response_, device_manager_->GetSyncedDevices(), pref_service_);
@@ -1051,7 +1052,7 @@
   cryptauth::GetMyDevicesResponse response;
   response.add_devices()->CopyFrom(device_with_only_public_key);
   response.add_devices()->CopyFrom(device_with_all_fields);
-  success_callback_.Run(response);
+  std::move(success_callback_).Run(response);
 
   ExpectSyncedDevicesAndPrefAreEqual(
       expected_devices, device_manager_->GetSyncedDevices(), pref_service_);
@@ -1065,7 +1066,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   // All synced devices.
   ExpectSyncedDevicesAndPrefAreEqual(
@@ -1100,7 +1101,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   cryptauth::ExternalDeviceInfo synced_device =
       device_manager_->GetSyncedDevices()[2];
@@ -1151,7 +1152,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   cryptauth::ExternalDeviceInfo synced_device =
       device_manager_->GetSyncedDevices()[2];
@@ -1202,7 +1203,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(get_my_devices_response_);
+  std::move(success_callback_).Run(get_my_devices_response_);
 
   cryptauth::ExternalDeviceInfo synced_device =
       device_manager_->GetSyncedDevices()[2];
@@ -1267,7 +1268,7 @@
   EXPECT_CALL(*this, OnSyncFinishedProxy(
                          CryptAuthDeviceManager::SyncResult::SUCCESS,
                          CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
-  success_callback_.Run(response);
+  std::move(success_callback_).Run(response);
 
   histogram_tester.ExpectTotalCount(
       "CryptAuth.DeviceSyncSoftwareFeaturesResult", 4);
diff --git a/chromeos/services/device_sync/cryptauth_device_notifier_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_device_notifier_impl_unittest.cc
index c3d247c..843074a 100644
--- a/chromeos/services/device_sync/cryptauth_device_notifier_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_device_notifier_impl_unittest.cc
@@ -186,8 +186,8 @@
  private:
   void OnBatchNotifyGroupDevices(
       const cryptauthv2::BatchNotifyGroupDevicesRequest& request,
-      const CryptAuthClient::BatchNotifyGroupDevicesCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::BatchNotifyGroupDevicesCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     batch_notify_group_devices_requests_.push(request);
     batch_notify_group_devices_success_callbacks_.push(std::move(callback));
     batch_notify_group_devices_failure_callbacks_.push(
diff --git a/chromeos/services/device_sync/cryptauth_enroller_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_enroller_impl_unittest.cc
index 8442f1a..3b50c42d 100644
--- a/chromeos/services/device_sync/cryptauth_enroller_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_enroller_impl_unittest.cc
@@ -211,10 +211,9 @@
     enroller_result_.reset(new bool(success));
   }
 
-  void OnSetupEnrollment(
-      const cryptauth::SetupEnrollmentRequest& request,
-      const CryptAuthClient::SetupEnrollmentCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+  void OnSetupEnrollment(const cryptauth::SetupEnrollmentRequest& request,
+                         CryptAuthClient::SetupEnrollmentCallback callback,
+                         CryptAuthClient::ErrorCallback error_callback) {
     // Check that SetupEnrollment is called before FinishEnrollment.
     EXPECT_FALSE(setup_request_.get());
     EXPECT_FALSE(finish_request_.get());
@@ -222,22 +221,21 @@
     EXPECT_TRUE(error_callback_.is_null());
 
     setup_request_.reset(new cryptauth::SetupEnrollmentRequest(request));
-    setup_callback_ = callback;
-    error_callback_ = error_callback;
+    setup_callback_ = std::move(callback);
+    error_callback_ = std::move(error_callback);
   }
 
-  void OnFinishEnrollment(
-      const cryptauth::FinishEnrollmentRequest& request,
-      const CryptAuthClient::FinishEnrollmentCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+  void OnFinishEnrollment(const cryptauth::FinishEnrollmentRequest& request,
+                          CryptAuthClient::FinishEnrollmentCallback callback,
+                          CryptAuthClient::ErrorCallback error_callback) {
     // Check that FinishEnrollment is called after SetupEnrollment.
     EXPECT_TRUE(setup_request_.get());
     EXPECT_FALSE(finish_request_.get());
     EXPECT_TRUE(finish_callback_.is_null());
 
     finish_request_.reset(new cryptauth::FinishEnrollmentRequest(request));
-    finish_callback_ = callback;
-    error_callback_ = error_callback;
+    finish_callback_ = std::move(callback);
+    error_callback_ = std::move(error_callback);
   }
 
   // The persistent user key-pair.
@@ -273,7 +271,7 @@
   ASSERT_EQ(1, setup_request_->types_size());
   EXPECT_EQ(kSupportedEnrollmentTypeGcmV1, setup_request_->types(0));
   ASSERT_FALSE(setup_callback_.is_null());
-  setup_callback_.Run(GetSetupEnrollmentResponse(true));
+  std::move(setup_callback_).Run(GetSetupEnrollmentResponse(true));
 
   // Handle FinishEnrollment request.
   EXPECT_TRUE(finish_request_.get());
@@ -283,7 +281,7 @@
   EXPECT_EQ(kInvocationReason, finish_request_->invocation_reason());
 
   ASSERT_FALSE(finish_callback_.is_null());
-  finish_callback_.Run(GetFinishEnrollmentResponse(true));
+  std::move(finish_callback_).Run(GetFinishEnrollmentResponse(true));
 
   ASSERT_TRUE(enroller_result_.get());
   EXPECT_TRUE(*enroller_result_);
@@ -294,7 +292,7 @@
 
   EXPECT_TRUE(setup_request_.get());
   ASSERT_FALSE(error_callback_.is_null());
-  error_callback_.Run(NetworkRequestError::kBadRequest);
+  std::move(error_callback_).Run(NetworkRequestError::kBadRequest);
 
   EXPECT_TRUE(finish_callback_.is_null());
   ASSERT_TRUE(enroller_result_.get());
@@ -305,7 +303,7 @@
   StartEnroller(GetDeviceInfo());
 
   EXPECT_TRUE(setup_request_.get());
-  setup_callback_.Run(GetSetupEnrollmentResponse(false));
+  std::move(setup_callback_).Run(GetSetupEnrollmentResponse(false));
 
   EXPECT_TRUE(finish_callback_.is_null());
   ASSERT_TRUE(enroller_result_.get());
@@ -317,7 +315,7 @@
   EXPECT_TRUE(setup_request_.get());
   cryptauth::SetupEnrollmentResponse response;
   response.set_status(kResponseStatusOk);
-  setup_callback_.Run(response);
+  std::move(setup_callback_).Run(response);
 
   EXPECT_TRUE(finish_callback_.is_null());
   ASSERT_TRUE(enroller_result_.get());
@@ -326,26 +324,26 @@
 
 TEST_F(DeviceSyncCryptAuthEnrollerTest, FinishEnrollmentApiCallError) {
   StartEnroller(GetDeviceInfo());
-  setup_callback_.Run(GetSetupEnrollmentResponse(true));
+  std::move(setup_callback_).Run(GetSetupEnrollmentResponse(true));
   ASSERT_FALSE(error_callback_.is_null());
-  error_callback_.Run(NetworkRequestError::kAuthenticationError);
+  std::move(error_callback_).Run(NetworkRequestError::kAuthenticationError);
   ASSERT_TRUE(enroller_result_.get());
   EXPECT_FALSE(*enroller_result_);
 }
 
 TEST_F(DeviceSyncCryptAuthEnrollerTest, FinishEnrollmentBadStatus) {
   StartEnroller(GetDeviceInfo());
-  setup_callback_.Run(GetSetupEnrollmentResponse(true));
+  std::move(setup_callback_).Run(GetSetupEnrollmentResponse(true));
   ASSERT_FALSE(finish_callback_.is_null());
-  finish_callback_.Run(GetFinishEnrollmentResponse(false));
+  std::move(finish_callback_).Run(GetFinishEnrollmentResponse(false));
   ASSERT_TRUE(enroller_result_.get());
   EXPECT_FALSE(*enroller_result_);
 }
 
 TEST_F(DeviceSyncCryptAuthEnrollerTest, ReuseEnroller) {
   StartEnroller(GetDeviceInfo());
-  setup_callback_.Run(GetSetupEnrollmentResponse(true));
-  finish_callback_.Run(GetFinishEnrollmentResponse(true));
+  std::move(setup_callback_).Run(GetSetupEnrollmentResponse(true));
+  std::move(finish_callback_).Run(GetFinishEnrollmentResponse(true));
   EXPECT_TRUE(*enroller_result_);
 
   StartEnroller(GetDeviceInfo());
diff --git a/chromeos/services/device_sync/cryptauth_feature_status_getter_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_feature_status_getter_impl_unittest.cc
index 357bc80..2f2588a 100644
--- a/chromeos/services/device_sync/cryptauth_feature_status_getter_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_feature_status_getter_impl_unittest.cc
@@ -217,15 +217,15 @@
  private:
   void OnBatchGetFeatureStatuses(
       const cryptauthv2::BatchGetFeatureStatusesRequest& request,
-      const CryptAuthClient::BatchGetFeatureStatusesCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::BatchGetFeatureStatusesCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     EXPECT_FALSE(batch_get_feature_statuses_request_);
     EXPECT_FALSE(batch_get_feature_statuses_success_callback_);
     EXPECT_FALSE(batch_get_feature_statuses_failure_callback_);
 
     batch_get_feature_statuses_request_ = request;
-    batch_get_feature_statuses_success_callback_ = callback;
-    batch_get_feature_statuses_failure_callback_ = error_callback;
+    batch_get_feature_statuses_success_callback_ = std::move(callback);
+    batch_get_feature_statuses_failure_callback_ = std::move(error_callback);
   }
 
   void OnGetFeatureStatusesComplete(
diff --git a/chromeos/services/device_sync/cryptauth_feature_status_setter_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_feature_status_setter_impl_unittest.cc
index 10fd2e8c..c6163b86 100644
--- a/chromeos/services/device_sync/cryptauth_feature_status_setter_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_feature_status_setter_impl_unittest.cc
@@ -212,8 +212,8 @@
  private:
   void OnBatchSetFeatureStatuses(
       const cryptauthv2::BatchSetFeatureStatusesRequest& request,
-      const CryptAuthClient::BatchSetFeatureStatusesCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::BatchSetFeatureStatusesCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     batch_set_feature_statuses_requests_.push(request);
     batch_set_feature_statuses_success_callbacks_.push(std::move(callback));
     batch_set_feature_statuses_failure_callbacks_.push(
diff --git a/chromeos/services/device_sync/cryptauth_group_private_key_sharer_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_group_private_key_sharer_impl_unittest.cc
index e2120cb..ba26d6d 100644
--- a/chromeos/services/device_sync/cryptauth_group_private_key_sharer_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_group_private_key_sharer_impl_unittest.cc
@@ -245,15 +245,15 @@
 
   void OnShareGroupPrivateKey(
       const cryptauthv2::ShareGroupPrivateKeyRequest& request,
-      const CryptAuthClient::ShareGroupPrivateKeyCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::ShareGroupPrivateKeyCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     EXPECT_FALSE(share_group_private_key_request_);
     EXPECT_FALSE(share_group_private_key_success_callback_);
     EXPECT_FALSE(share_group_private_key_failure_callback_);
 
     share_group_private_key_request_ = request;
-    share_group_private_key_success_callback_ = callback;
-    share_group_private_key_failure_callback_ = error_callback;
+    share_group_private_key_success_callback_ = std::move(callback);
+    share_group_private_key_failure_callback_ = std::move(error_callback);
   }
 
   void OnShareGroupPrivateKeyComplete(
diff --git a/chromeos/services/device_sync/cryptauth_metadata_syncer_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_metadata_syncer_impl_unittest.cc
index 28790dc..8fcb4835 100644
--- a/chromeos/services/device_sync/cryptauth_metadata_syncer_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_metadata_syncer_impl_unittest.cc
@@ -292,10 +292,9 @@
   base::MockOneShotTimer* timer() { return timer_; }
 
  private:
-  void OnSyncMetadataResponse(
-      const cryptauthv2::SyncMetadataRequest& request,
-      const CryptAuthClient::SyncMetadataCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+  void OnSyncMetadataResponse(const cryptauthv2::SyncMetadataRequest& request,
+                              CryptAuthClient::SyncMetadataCallback callback,
+                              CryptAuthClient::ErrorCallback error_callback) {
     ++num_sync_metadata_calls_;
     EXPECT_LE(num_sync_metadata_calls_, 2u);
 
@@ -309,16 +308,16 @@
       EXPECT_FALSE(first_sync_metadata_failure_callback_);
 
       first_sync_metadata_request_ = request;
-      first_sync_metadata_success_callback_ = callback;
-      first_sync_metadata_failure_callback_ = error_callback;
+      first_sync_metadata_success_callback_ = std::move(callback);
+      first_sync_metadata_failure_callback_ = std::move(error_callback);
     } else if (num_sync_metadata_calls_ == 2) {
       EXPECT_TRUE(first_sync_metadata_request_);
       EXPECT_FALSE(first_sync_metadata_success_callback_);
       EXPECT_TRUE(first_sync_metadata_failure_callback_);
 
       second_sync_metadata_request_ = request;
-      second_sync_metadata_success_callback_ = callback;
-      second_sync_metadata_failure_callback_ = error_callback;
+      second_sync_metadata_success_callback_ = std::move(callback);
+      second_sync_metadata_failure_callback_ = std::move(error_callback);
     }
   }
 
diff --git a/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc
index 633794f0..608078c 100644
--- a/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_v2_enroller_impl_unittest.cc
@@ -347,8 +347,8 @@
   }
 
   void OnSyncKeys(const SyncKeysRequest& request,
-                  const CryptAuthClient::SyncKeysCallback& callback,
-                  const CryptAuthClient::ErrorCallback& error_callback) {
+                  CryptAuthClient::SyncKeysCallback callback,
+                  CryptAuthClient::ErrorCallback error_callback) {
     // Check that SyncKeys is called before EnrollKeys.
     EXPECT_FALSE(sync_keys_request_);
     EXPECT_FALSE(enroll_keys_request_);
@@ -358,8 +358,8 @@
     EXPECT_TRUE(enroll_keys_failure_callback_.is_null());
 
     sync_keys_request_ = request;
-    sync_keys_success_callback_ = callback;
-    sync_keys_failure_callback_ = error_callback;
+    sync_keys_success_callback_ = std::move(callback);
+    sync_keys_failure_callback_ = std::move(error_callback);
   }
 
   void SendSyncKeysResponse(const SyncKeysResponse& sync_keys_response) {
@@ -387,8 +387,8 @@
   }
 
   void OnEnrollKeys(const EnrollKeysRequest& request,
-                    const CryptAuthClient::EnrollKeysCallback& callback,
-                    const CryptAuthClient::ErrorCallback& error_callback) {
+                    CryptAuthClient::EnrollKeysCallback callback,
+                    CryptAuthClient::ErrorCallback error_callback) {
     // Check that EnrollKeys is called after a successful SyncKeys call.
     EXPECT_TRUE(sync_keys_request_);
     EXPECT_FALSE(enroll_keys_request_);
@@ -398,8 +398,8 @@
     EXPECT_TRUE(enroll_keys_failure_callback_.is_null());
 
     enroll_keys_request_ = request;
-    enroll_keys_success_callback_ = callback;
-    enroll_keys_failure_callback_ = error_callback;
+    enroll_keys_success_callback_ = std::move(callback);
+    enroll_keys_failure_callback_ = std::move(error_callback);
   }
 
   void VerifyKeyCreatorInputs(
diff --git a/chromeos/services/device_sync/mock_cryptauth_client.h b/chromeos/services/device_sync/mock_cryptauth_client.h
index 7ef16a8a..5996009 100644
--- a/chromeos/services/device_sync/mock_cryptauth_client.h
+++ b/chromeos/services/device_sync/mock_cryptauth_client.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_SERVICES_DEVICE_SYNC_MOCK_CRYPTAUTH_CLIENT_H_
 #define CHROMEOS_SERVICES_DEVICE_SYNC_MOCK_CRYPTAUTH_CLIENT_H_
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "chromeos/services/device_sync/cryptauth_client.h"
@@ -24,70 +25,78 @@
 
   // TODO(https://crbug.com/997268): Update these to use MOCK_METHOD.
   // CryptAuthClient:
-  MOCK_METHOD4(GetMyDevices,
+  void GetMyDevices(const cryptauth::GetMyDevicesRequest& request,
+                    GetMyDevicesCallback callback,
+                    ErrorCallback error_callback,
+                    const net::PartialNetworkTrafficAnnotationTag&
+                        partial_traffic_annotation) override {
+    GetMyDevices_(request, callback, error_callback,
+                  partial_traffic_annotation);
+  }
+  MOCK_METHOD4(GetMyDevices_,
                void(const cryptauth::GetMyDevicesRequest& request,
-                    const GetMyDevicesCallback& callback,
-                    const ErrorCallback& error_callback,
+                    GetMyDevicesCallback& callback,
+                    ErrorCallback& error_callback,
                     const net::PartialNetworkTrafficAnnotationTag&
                         partial_traffic_annotation));
   MOCK_METHOD3(FindEligibleUnlockDevices,
                void(const cryptauth::FindEligibleUnlockDevicesRequest& request,
-                    const FindEligibleUnlockDevicesCallback& callback,
-                    const ErrorCallback& error_callback));
+                    FindEligibleUnlockDevicesCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(FindEligibleForPromotion,
                void(const cryptauth::FindEligibleForPromotionRequest& request,
-                    const FindEligibleForPromotionCallback& callback,
-                    const ErrorCallback& error_callback));
+                    FindEligibleForPromotionCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD4(SendDeviceSyncTickle,
                void(const cryptauth::SendDeviceSyncTickleRequest& request,
-                    const SendDeviceSyncTickleCallback& callback,
-                    const ErrorCallback& error_callback,
+                    SendDeviceSyncTickleCallback callback,
+                    ErrorCallback error_callback,
                     const net::PartialNetworkTrafficAnnotationTag&
                         partial_traffic_annotation));
   MOCK_METHOD3(ToggleEasyUnlock,
                void(const cryptauth::ToggleEasyUnlockRequest& request,
-                    const ToggleEasyUnlockCallback& callback,
-                    const ErrorCallback& error_callback));
+                    ToggleEasyUnlockCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(SetupEnrollment,
                void(const cryptauth::SetupEnrollmentRequest& request,
-                    const SetupEnrollmentCallback& callback,
-                    const ErrorCallback& error_callback));
+                    SetupEnrollmentCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(FinishEnrollment,
                void(const cryptauth::FinishEnrollmentRequest& request,
-                    const FinishEnrollmentCallback& callback,
-                    const ErrorCallback& error_callback));
+                    FinishEnrollmentCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(SyncKeys,
                void(const cryptauthv2::SyncKeysRequest& request,
-                    const SyncKeysCallback& callback,
-                    const ErrorCallback& error_callback));
+                    SyncKeysCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(EnrollKeys,
                void(const cryptauthv2::EnrollKeysRequest& request,
-                    const EnrollKeysCallback& callback,
-                    const ErrorCallback& error_callback));
+                    EnrollKeysCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(SyncMetadata,
                void(const cryptauthv2::SyncMetadataRequest& request,
-                    const SyncMetadataCallback& callback,
-                    const ErrorCallback& error_callback));
+                    SyncMetadataCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(ShareGroupPrivateKey,
                void(const cryptauthv2::ShareGroupPrivateKeyRequest& request,
-                    const ShareGroupPrivateKeyCallback& callback,
-                    const ErrorCallback& error_callback));
+                    ShareGroupPrivateKeyCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(BatchNotifyGroupDevices,
                void(const cryptauthv2::BatchNotifyGroupDevicesRequest& request,
-                    const BatchNotifyGroupDevicesCallback& callback,
-                    const ErrorCallback& error_callback));
+                    BatchNotifyGroupDevicesCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(BatchGetFeatureStatuses,
                void(const cryptauthv2::BatchGetFeatureStatusesRequest& request,
-                    const BatchGetFeatureStatusesCallback& callback,
-                    const ErrorCallback& error_callback));
+                    BatchGetFeatureStatusesCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(BatchSetFeatureStatuses,
                void(const cryptauthv2::BatchSetFeatureStatusesRequest& request,
-                    const BatchSetFeatureStatusesCallback& callback,
-                    const ErrorCallback& error_callback));
+                    BatchSetFeatureStatusesCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD3(GetDevicesActivityStatus,
                void(const cryptauthv2::GetDevicesActivityStatusRequest& request,
-                    const GetDevicesActivityStatusCallback& callback,
-                    const ErrorCallback& error_callback));
+                    GetDevicesActivityStatusCallback callback,
+                    ErrorCallback error_callback));
   MOCK_METHOD0(GetAccessTokenUsed, std::string());
 
  private:
diff --git a/chromeos/services/device_sync/software_feature_manager_impl_unittest.cc b/chromeos/services/device_sync/software_feature_manager_impl_unittest.cc
index db9d622a..6587bcf0 100644
--- a/chromeos/services/device_sync/software_feature_manager_impl_unittest.cc
+++ b/chromeos/services/device_sync/software_feature_manager_impl_unittest.cc
@@ -113,24 +113,23 @@
   }
 
   // Mock CryptAuthClient::ToggleEasyUnlock() implementation.
-  void MockToggleEasyUnlock(
-      const cryptauth::ToggleEasyUnlockRequest& request,
-      const CryptAuthClient::ToggleEasyUnlockCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+  void MockToggleEasyUnlock(const cryptauth::ToggleEasyUnlockRequest& request,
+                            CryptAuthClient::ToggleEasyUnlockCallback callback,
+                            CryptAuthClient::ErrorCallback error_callback) {
     last_toggle_request_ = request;
-    toggle_easy_unlock_callback_ = callback;
-    error_callback_ = error_callback;
+    toggle_easy_unlock_callback_ = std::move(callback);
+    error_callback_ = std::move(error_callback);
     error_code_ = kErrorSettingSoftwareFeatureNetworkRequestError;
   }
 
   // Mock CryptAuthClient::FindEligibleUnlockDevices() implementation.
   void MockFindEligibleUnlockDevices(
       const cryptauth::FindEligibleUnlockDevicesRequest& request,
-      const CryptAuthClient::FindEligibleUnlockDevicesCallback& callback,
-      const CryptAuthClient::ErrorCallback& error_callback) {
+      CryptAuthClient::FindEligibleUnlockDevicesCallback callback,
+      CryptAuthClient::ErrorCallback error_callback) {
     last_find_request_ = request;
-    find_eligible_unlock_devices_callback_ = callback;
-    error_callback_ = error_callback;
+    find_eligible_unlock_devices_callback_ = std::move(callback);
+    error_callback_ = std::move(error_callback);
     error_code_ = kErrorFindingEligibleNetworkRequestError;
   }
 
@@ -259,10 +258,9 @@
 
   void InvokeSetSoftwareFeatureCallback() {
     CryptAuthClient::ToggleEasyUnlockCallback success_callback =
-        toggle_easy_unlock_callback_;
+        std::move(toggle_easy_unlock_callback_);
     ASSERT_TRUE(!success_callback.is_null());
-    toggle_easy_unlock_callback_.Reset();
-    success_callback.Run(cryptauth::ToggleEasyUnlockResponse());
+    std::move(success_callback).Run(cryptauth::ToggleEasyUnlockResponse());
   }
 
   void InvokeSetFeatureStatusCallback() {
@@ -282,17 +280,15 @@
       const cryptauth::FindEligibleUnlockDevicesResponse&
           retrieved_devices_response) {
     CryptAuthClient::FindEligibleUnlockDevicesCallback success_callback =
-        find_eligible_unlock_devices_callback_;
+        std::move(find_eligible_unlock_devices_callback_);
     ASSERT_TRUE(!success_callback.is_null());
-    find_eligible_unlock_devices_callback_.Reset();
-    success_callback.Run(retrieved_devices_response);
+    std::move(success_callback).Run(retrieved_devices_response);
   }
 
   void InvokeErrorCallback() {
-    CryptAuthClient::ErrorCallback error_callback = error_callback_;
+    CryptAuthClient::ErrorCallback error_callback = std::move(error_callback_);
     ASSERT_TRUE(!error_callback.is_null());
-    error_callback_.Reset();
-    error_callback.Run(*error_code_);
+    std::move(error_callback).Run(*error_code_);
   }
 
   void InvokeSetFeatureStatusErrorCallback() {
diff --git a/chromeos/services/secure_channel/error_tolerant_ble_advertisement.h b/chromeos/services/secure_channel/error_tolerant_ble_advertisement.h
index 7264b24..2f4a070 100644
--- a/chromeos/services/secure_channel/error_tolerant_ble_advertisement.h
+++ b/chromeos/services/secure_channel/error_tolerant_ble_advertisement.h
@@ -28,7 +28,7 @@
   // of simply deleting an ErrorTolerantBleAdvertisement object. Clients should
   // not assume that advertising has actually stopped until |callback| has been
   // invoked.
-  virtual void Stop(const base::Closure& callback) = 0;
+  virtual void Stop(base::OnceClosure callback) = 0;
 
   // Returns whether Stop() has been called.
   virtual bool HasBeenStopped() = 0;
diff --git a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.cc b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.cc
index ede407d5..532100f 100644
--- a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.cc
+++ b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.cc
@@ -67,16 +67,18 @@
     advertisement_->RemoveObserver(this);
 }
 
-void ErrorTolerantBleAdvertisementImpl::Stop(const base::Closure& callback) {
+void ErrorTolerantBleAdvertisementImpl::Stop(base::OnceClosure callback) {
   // Stop() should only be called once per instance.
+  DCHECK(!stopped_);
   DCHECK(stop_callback_.is_null());
 
-  stop_callback_ = callback;
+  stopped_ = true;
+  stop_callback_ = std::move(callback);
   UpdateRegistrationStatus();
 }
 
 bool ErrorTolerantBleAdvertisementImpl::HasBeenStopped() {
-  return !stop_callback_.is_null();
+  return stopped_;
 }
 
 void ErrorTolerantBleAdvertisementImpl::AdvertisementReleased(
@@ -119,9 +121,10 @@
 
   ble_synchronizer_->RegisterAdvertisement(
       std::move(advertisement_data),
-      base::Bind(&ErrorTolerantBleAdvertisementImpl::OnAdvertisementRegistered,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(
+      base::BindOnce(
+          &ErrorTolerantBleAdvertisementImpl::OnAdvertisementRegistered,
+          weak_ptr_factory_.GetWeakPtr()),
+      base::BindOnce(
           &ErrorTolerantBleAdvertisementImpl::OnErrorRegisteringAdvertisement,
           weak_ptr_factory_.GetWeakPtr()));
 }
@@ -140,10 +143,10 @@
 
   ble_synchronizer_->UnregisterAdvertisement(
       advertisement_,
-      base::Bind(
+      base::BindOnce(
           &ErrorTolerantBleAdvertisementImpl::OnAdvertisementUnregistered,
           weak_ptr_factory_.GetWeakPtr()),
-      base::Bind(
+      base::BindOnce(
           &ErrorTolerantBleAdvertisementImpl::OnErrorUnregisteringAdvertisement,
           weak_ptr_factory_.GetWeakPtr()));
 }
@@ -207,7 +210,7 @@
   advertisement_ = nullptr;
 
   DCHECK(!stop_callback_.is_null());
-  stop_callback_.Run();
+  std::move(stop_callback_).Run();
 }
 
 void ErrorTolerantBleAdvertisementImpl::OnErrorUnregisteringAdvertisement(
diff --git a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h
index 1d8f72c..b40e235 100644
--- a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h
+++ b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl.h
@@ -56,7 +56,7 @@
       BleSynchronizerBase* ble_synchronizer);
 
   // ErrorTolerantBleAdvertisement:
-  void Stop(const base::Closure& callback) override;
+  void Stop(base::OnceClosure callback) override;
   bool HasBeenStopped() override;
 
   // device::BluetoothAdvertisement::Observer
@@ -93,7 +93,8 @@
 
   scoped_refptr<device::BluetoothAdvertisement> advertisement_;
 
-  base::Closure stop_callback_;
+  bool stopped_ = false;
+  base::OnceClosure stop_callback_;
 
   base::WeakPtrFactory<ErrorTolerantBleAdvertisementImpl> weak_ptr_factory_{
       this};
diff --git a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl_unittest.cc b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl_unittest.cc
index 1d462df4..645255c 100644
--- a/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl_unittest.cc
+++ b/chromeos/services/secure_channel/error_tolerant_ble_advertisement_impl_unittest.cc
@@ -97,7 +97,7 @@
   }
 
   void CallStop() {
-    advertisement_->Stop(base::Bind(
+    advertisement_->Stop(base::BindOnce(
         &SecureChannelErrorTolerantBleAdvertisementImplTest::OnStopped,
         base::Unretained(this)));
   }
diff --git a/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.cc b/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.cc
index 0599d2e1..03ae07872 100644
--- a/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.cc
+++ b/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.cc
@@ -22,17 +22,18 @@
 }
 
 bool FakeErrorTolerantBleAdvertisement::HasBeenStopped() {
-  return !stop_callback_.is_null();
+  return stopped_;
 }
 
 void FakeErrorTolerantBleAdvertisement::InvokeStopCallback() {
   DCHECK(HasBeenStopped());
-  stop_callback_.Run();
+  std::move(stop_callback_).Run();
 }
 
-void FakeErrorTolerantBleAdvertisement::Stop(const base::Closure& callback) {
+void FakeErrorTolerantBleAdvertisement::Stop(base::OnceClosure callback) {
   DCHECK(!HasBeenStopped());
-  stop_callback_ = callback;
+  stopped_ = true;
+  stop_callback_ = std::move(callback);
 }
 
 }  // namespace secure_channel
diff --git a/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.h b/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.h
index af27df4..cc8af60 100644
--- a/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.h
+++ b/chromeos/services/secure_channel/fake_error_tolerant_ble_advertisement.h
@@ -28,13 +28,14 @@
   void InvokeStopCallback();
 
   // ErrorTolerantBleAdvertisement:
-  void Stop(const base::Closure& callback) override;
+  void Stop(base::OnceClosure callback) override;
   bool HasBeenStopped() override;
 
  private:
   base::UnguessableToken id_;
   base::OnceCallback<void(const DeviceIdPair&)> destructor_callback_;
-  base::Closure stop_callback_;
+  base::OnceClosure stop_callback_;
+  bool stopped_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(FakeErrorTolerantBleAdvertisement);
 };
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index f209925..3476442 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -418,7 +418,7 @@
     "//chromeos/network:test_support",
     "//chromeos/system:system",
     "//components/account_id",
-    "//components/arc/video_accelerator",
+    "//components/arc/video_accelerator:common",
     "//components/keyed_service/content",
     "//components/prefs:test_support",
     "//components/session_manager/core:core",
diff --git a/components/arc/mojom/video_accelerator_mojom_traits.cc b/components/arc/mojom/video_accelerator_mojom_traits.cc
index d714953..1000ca0 100644
--- a/components/arc/mojom/video_accelerator_mojom_traits.cc
+++ b/components/arc/mojom/video_accelerator_mojom_traits.cc
@@ -4,9 +4,6 @@
 
 #include "components/arc/mojom/video_accelerator_mojom_traits.h"
 
-#include "base/files/platform_file.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-
 namespace mojo {
 
 // Make sure values in arc::mojom::VideoCodecProfile match to the values in
@@ -173,48 +170,6 @@
   return false;
 }
 
-// Make sure values in arc::mojom::DecodeStatus match to the values in
-// media::DecodeStatus.
-#define CHECK_DECODE_STATUS_ENUM(value)                              \
-  static_assert(static_cast<int>(arc::mojom::DecodeStatus::value) == \
-                    static_cast<int>(media::DecodeStatus::value),    \
-                "enum ##value mismatch")
-
-CHECK_DECODE_STATUS_ENUM(OK);
-CHECK_DECODE_STATUS_ENUM(ABORTED);
-CHECK_DECODE_STATUS_ENUM(DECODE_ERROR);
-
-#undef CHECK_DECODE_STATUS_ENUM
-
-// static
-arc::mojom::DecodeStatus
-EnumTraits<arc::mojom::DecodeStatus, media::DecodeStatus>::ToMojom(
-    media::DecodeStatus input) {
-  switch (input) {
-    case media::DecodeStatus::OK:
-    case media::DecodeStatus::ABORTED:
-    case media::DecodeStatus::DECODE_ERROR:
-      return static_cast<arc::mojom::DecodeStatus>(input);
-  }
-  NOTREACHED() << "unknown status: " << static_cast<int>(input);
-  return arc::mojom::DecodeStatus::DECODE_ERROR;
-}
-
-// static
-bool EnumTraits<arc::mojom::DecodeStatus, media::DecodeStatus>::FromMojom(
-    arc::mojom::DecodeStatus input,
-    media::DecodeStatus* output) {
-  switch (input) {
-    case arc::mojom::DecodeStatus::OK:
-    case arc::mojom::DecodeStatus::ABORTED:
-    case arc::mojom::DecodeStatus::DECODE_ERROR:
-      *output = static_cast<media::DecodeStatus>(input);
-      return true;
-  }
-  NOTREACHED() << "unknown status: " << static_cast<int>(input);
-  return false;
-}
-
 // static
 bool StructTraits<arc::mojom::VideoFramePlaneDataView, arc::VideoFramePlane>::
     Read(arc::mojom::VideoFramePlaneDataView data, arc::VideoFramePlane* out) {
@@ -272,49 +227,4 @@
   return true;
 }
 
-// static
-bool StructTraits<arc::mojom::VideoFrameDataView,
-                  scoped_refptr<media::VideoFrame>>::
-    Read(arc::mojom::VideoFrameDataView data,
-         scoped_refptr<media::VideoFrame>* out) {
-  gfx::Rect visible_rect;
-  if (data.id() == 0 || !data.ReadVisibleRect(&visible_rect)) {
-    return false;
-  }
-
-  // We store id at the first 8 byte of the mailbox.
-  const uint64_t id = data.id();
-  static_assert(GL_MAILBOX_SIZE_CHROMIUM >= sizeof(id),
-                "Size of Mailbox is too small to store id.");
-  gpu::Mailbox mailbox;
-  memcpy(mailbox.name, &id, sizeof(id));
-  gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes];
-  mailbox_holders[0] = gpu::MailboxHolder(mailbox, gpu::SyncToken(), 0);
-
-  // We don't store pixel format and coded_size in Mojo struct. Use dummy value.
-  *out = media::VideoFrame::WrapNativeTextures(
-      media::PIXEL_FORMAT_I420, mailbox_holders,
-      media::VideoFrame::ReleaseMailboxCB(), visible_rect.size(), visible_rect,
-      visible_rect.size(), base::TimeDelta::FromMilliseconds(data.timestamp()));
-  return true;
-}
-
-// static
-bool StructTraits<arc::mojom::DecoderBufferDataView, arc::DecoderBuffer>::Read(
-    arc::mojom::DecoderBufferDataView data,
-    arc::DecoderBuffer* out) {
-  base::PlatformFile platform_file = base::kInvalidPlatformFile;
-  if (mojo::UnwrapPlatformFile(data.TakeHandleFd(), &platform_file) !=
-      MOJO_RESULT_OK) {
-    return false;
-  }
-
-  out->handle_fd = base::ScopedFD(platform_file);
-  out->offset = data.offset();
-  out->payload_size = data.payload_size();
-  out->end_of_stream = data.end_of_stream();
-  out->timestamp = base::TimeDelta::FromMilliseconds(data.timestamp());
-  return true;
-}
-
 }  // namespace mojo
diff --git a/components/arc/mojom/video_accelerator_mojom_traits.h b/components/arc/mojom/video_accelerator_mojom_traits.h
index 06bc2e6..845aac4 100644
--- a/components/arc/mojom/video_accelerator_mojom_traits.h
+++ b/components/arc/mojom/video_accelerator_mojom_traits.h
@@ -5,22 +5,14 @@
 #ifndef COMPONENTS_ARC_MOJOM_VIDEO_ACCELERATOR_MOJOM_TRAITS_H_
 #define COMPONENTS_ARC_MOJOM_VIDEO_ACCELERATOR_MOJOM_TRAITS_H_
 
-#include <string.h>
-
 #include <memory>
 
-#include "components/arc/mojom/arc_gfx_mojom_traits.h"
 #include "components/arc/mojom/video_common.mojom.h"
-#include "components/arc/video_accelerator/decoder_buffer.h"
 #include "components/arc/video_accelerator/video_frame_plane.h"
 #include "media/base/color_plane_layout.h"
-#include "media/base/decode_status.h"
 #include "media/base/video_codecs.h"
-#include "media/base/video_frame.h"
 #include "media/base/video_frame_layout.h"
 #include "media/base/video_types.h"
-#include "mojo/public/cpp/platform/platform_handle.h"
-#include "mojo/public/cpp/system/platform_handle.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace mojo {
@@ -139,81 +131,6 @@
                    std::unique_ptr<media::VideoFrameLayout>* out);
 };
 
-template <>
-struct EnumTraits<arc::mojom::DecodeStatus, media::DecodeStatus> {
-  static arc::mojom::DecodeStatus ToMojom(media::DecodeStatus input);
-
-  static bool FromMojom(arc::mojom::DecodeStatus input,
-                        media::DecodeStatus* output);
-};
-
-template <>
-struct StructTraits<arc::mojom::VideoFrameDataView,
-                    scoped_refptr<media::VideoFrame>> {
-  static bool IsNull(const scoped_refptr<media::VideoFrame> input) {
-    return !input;
-  }
-
-  static void SetToNull(scoped_refptr<media::VideoFrame>* output) {
-    output->reset();
-  }
-
-  static uint64_t id(const scoped_refptr<media::VideoFrame> input) {
-    DCHECK(input);
-    DCHECK(!input->mailbox_holder(0).mailbox.IsZero());
-
-    // We store id at the first 8 byte of the mailbox.
-    uint64_t id;
-    static_assert(GL_MAILBOX_SIZE_CHROMIUM >= sizeof(id),
-                  "Size of Mailbox is too small to store id.");
-    const int8_t* const name = input->mailbox_holder(0).mailbox.name;
-    memcpy(&id, name, sizeof(id));
-    return id;
-  }
-
-  static gfx::Rect visible_rect(const scoped_refptr<media::VideoFrame> input) {
-    DCHECK(input);
-
-    return input->visible_rect();
-  }
-
-  static int64_t timestamp(const scoped_refptr<media::VideoFrame> input) {
-    DCHECK(input);
-
-    return input->timestamp().InMilliseconds();
-  }
-
-  static bool Read(arc::mojom::VideoFrameDataView data,
-                   scoped_refptr<media::VideoFrame>* out);
-};
-
-template <>
-struct StructTraits<arc::mojom::DecoderBufferDataView, arc::DecoderBuffer> {
-  static mojo::ScopedHandle handle_fd(arc::DecoderBuffer& input) {
-    return mojo::WrapPlatformHandle(
-        mojo::PlatformHandle(std::move(input.handle_fd)));
-  }
-
-  static uint32_t offset(const arc::DecoderBuffer& input) {
-    return input.offset;
-  }
-
-  static uint32_t payload_size(const arc::DecoderBuffer& input) {
-    return input.payload_size;
-  }
-
-  static bool end_of_stream(const arc::DecoderBuffer& input) {
-    return input.end_of_stream;
-  }
-
-  static int64_t timestamp(const arc::DecoderBuffer& input) {
-    return input.timestamp.InMilliseconds();
-  }
-
-  static bool Read(arc::mojom::DecoderBufferDataView data,
-                   arc::DecoderBuffer* out);
-};
-
 }  // namespace mojo
 
 #endif  // COMPONENTS_ARC_MOJOM_VIDEO_ACCELERATOR_MOJOM_TRAITS_H_
diff --git a/components/arc/mojom/video_accelerator_mojom_traits_unittest.cc b/components/arc/mojom/video_accelerator_mojom_traits_unittest.cc
index ad091dd..6b39ac5 100644
--- a/components/arc/mojom/video_accelerator_mojom_traits_unittest.cc
+++ b/components/arc/mojom/video_accelerator_mojom_traits_unittest.cc
@@ -6,11 +6,7 @@
 
 #include <vector>
 
-#include "base/files/file_util.h"
-#include "base/stl_util.h"
 #include "components/arc/mojom/video_common.mojom.h"
-#include "components/arc/video_accelerator/arc_video_accelerator_util.h"
-#include "components/arc/video_accelerator/decoder_buffer.h"
 #include "media/base/video_frame_layout.h"
 #include "media/base/video_types.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
@@ -19,7 +15,6 @@
 namespace mojo {
 
 namespace {
-constexpr int64_t kTimestamp = 1234;
 constexpr int kWidth = 640;
 constexpr int kHeight = 480;
 constexpr media::VideoPixelFormat kFormat = media::PIXEL_FORMAT_I420;
@@ -63,64 +58,4 @@
   EXPECT_FALSE(output);
 }
 
-TEST(VideoAcceleratorStructTraitsTest, ConvertVideoFrame) {
-  // We store id in the first 8 bytes of kMailbox.
-  gpu::Mailbox kMailbox;
-  kMailbox.name[0] = 0xff;
-  kMailbox.name[1] = 0xed;
-  kMailbox.name[2] = 0xfb;
-  kMailbox.name[3] = 0xea;
-  kMailbox.name[4] = 0xf9;
-  kMailbox.name[5] = 0x7e;
-  kMailbox.name[6] = 0xe5;
-  kMailbox.name[7] = 0xe3;
-
-  gpu::MailboxHolder mailbox_holders[media::VideoFrame::kMaxPlanes];
-  mailbox_holders[0] = gpu::MailboxHolder(kMailbox, gpu::SyncToken(), 0);
-
-  scoped_refptr<media::VideoFrame> input =
-      media::VideoFrame::WrapNativeTextures(
-          kFormat, mailbox_holders, media::VideoFrame::ReleaseMailboxCB(),
-          kCodedSize, gfx::Rect(kCodedSize), kCodedSize,
-          base::TimeDelta::FromMilliseconds(kTimestamp));
-  scoped_refptr<media::VideoFrame> output;
-  mojo::test::SerializeAndDeserialize<arc::mojom::VideoFrame>(&input, &output);
-
-  // Verify the fields of input and output frames.
-  EXPECT_EQ(output->mailbox_holder(0).mailbox, kMailbox);
-  EXPECT_EQ(output->visible_rect(), input->visible_rect());
-  EXPECT_EQ(output->timestamp(), input->timestamp());
-}
-
-TEST(VideoAcceleratorStructTraitsTest, ConvertNullVideoFrame) {
-  scoped_refptr<media::VideoFrame> input;
-  scoped_refptr<media::VideoFrame> output;
-  mojo::test::SerializeAndDeserialize<arc::mojom::VideoFrame>(&input, &output);
-
-  EXPECT_FALSE(output);
-}
-
-TEST(VideoAcceleratorStructTraitsTest, ConvertDecoderBuffer) {
-  const std::string kData = "TESTING_STRING";
-  const uint32_t kOffset = 3;
-  const uint32_t kDataSize = kData.size() - kOffset;
-  constexpr bool kEndOfStream = false;
-
-  arc::DecoderBuffer input(arc::CreateTempFileForTesting(kData), kOffset,
-                           kDataSize, kEndOfStream,
-                           base::TimeDelta::FromMilliseconds(kTimestamp));
-  arc::DecoderBuffer output;
-  mojo::test::SerializeAndDeserialize<arc::mojom::DecoderBuffer>(&input,
-                                                                 &output);
-
-  EXPECT_EQ(output.end_of_stream, input.end_of_stream);
-  EXPECT_EQ(output.timestamp, input.timestamp);
-  EXPECT_EQ(output.offset, input.offset);
-  EXPECT_EQ(output.payload_size, input.payload_size);
-
-  scoped_refptr<media::DecoderBuffer> buf =
-      std::move(output).ToMediaDecoderBuffer();
-  EXPECT_EQ(memcmp(kData.c_str() + kOffset, buf->data(), kDataSize), 0);
-}
-
 }  // namespace mojo
diff --git a/components/arc/mojom/video_common.mojom b/components/arc/mojom/video_common.mojom
index 66167ce..32078938 100644
--- a/components/arc/mojom/video_common.mojom
+++ b/components/arc/mojom/video_common.mojom
@@ -7,8 +7,6 @@
 
 module arc.mojom;
 
-import "components/arc/mojom/gfx.mojom";
-
 [Extensible]
 enum VideoCodecProfile {
   // The values must match to the values in media::VideoCodecProfile.
@@ -83,14 +81,6 @@
   [MinVersion=2] PIXEL_FORMAT_XBGR = 28,
 };
 
-[Extensible]
-enum DecodeStatus {
-  // The values must match to the values in media::DecodeStatus
-  OK = 0,
-  ABORTED = 1,
-  DECODE_ERROR = 2,
-};
-
 // The offset and stride of a video frame plane. Both offset and stride must
 // be non negative.
 struct VideoFramePlane {
@@ -122,29 +112,3 @@
   uint32 buffer_addr_align;
   uint64 modifier;
 };
-
-struct VideoFrame {
-  // Identifier of the buffer. The value of a valid frame should be non-zero.
-  uint64 id;
-  Rect visible_rect;
-  // timestamp in milliseconds.
-  int64 timestamp;
-};
-
-// Struct for storing bitstream buffer.
-struct DecoderBuffer {
-  // Field for a physical buffer. This buffer is passed over an interface from
-  // ARC++ to Chrome, with a callback method that will be run when the buffer is
-  // used and the file descriptor is closed.
-  handle handle_fd;
-  // Distance in bytes between the beginning of the buffer pointed by
-  // |handle_fd| and the beginning of bitstream buffer.
-  uint32 offset;
-  // Bitstream buffer size in bytes. The buffer length referred by |handle_fd|
-  // can be more than |offset| + |payload_size|.
-  uint32 payload_size;
-  // Whether the buffer is an end-of-stream (EOS) buffer.
-  bool end_of_stream;
-  // Timestamp in microseconds.
-  int64 timestamp;
-};
diff --git a/components/arc/mojom/video_common.typemap b/components/arc/mojom/video_common.typemap
index e6ebb5c..1890c206 100644
--- a/components/arc/mojom/video_common.typemap
+++ b/components/arc/mojom/video_common.typemap
@@ -4,18 +4,14 @@
 
 mojom = "//components/arc/mojom/video_common.mojom"
 public_headers = [
-  "//components/arc/video_accelerator/decoder_buffer.h",
   "//components/arc/video_accelerator/video_frame_plane.h",
   "//media/base/color_plane_layout.h",
-  "//media/base/decode_status.h",
   "//media/base/video_codecs.h",
-  "//media/base/video_frame.h",
   "//media/base/video_types.h",
   "//ui/gfx/geometry/size.h",
 ]
 
 public_deps = [
-  "//components/arc/video_accelerator:common",
   "//media",
 ]
 
@@ -27,16 +23,14 @@
 ]
 
 deps = [
+  "//components/arc/video_accelerator:common",
   "//ui/gfx/geometry",
 ]
 
 type_mappings = [
-  "arc.mojom.DecoderBuffer=arc::DecoderBuffer[move_only]",
-  "arc.mojom.DecodeStatus=media::DecodeStatus",
   "arc.mojom.ColorPlaneLayout=media::ColorPlaneLayout",
   "arc.mojom.Size=gfx::Size",
   "arc.mojom.VideoCodecProfile=media::VideoCodecProfile",
-  "arc.mojom.VideoFrame=scoped_refptr<media::VideoFrame>[nullable_is_same_type]",
 
   # media::VideoFrameLayout doesn't have default constructor, so we cannot
   # convert directly.
diff --git a/components/arc/video_accelerator/BUILD.gn b/components/arc/video_accelerator/BUILD.gn
index e764d97..086ca106 100644
--- a/components/arc/video_accelerator/BUILD.gn
+++ b/components/arc/video_accelerator/BUILD.gn
@@ -29,8 +29,6 @@
   sources = [
     "arc_video_accelerator_util.cc",
     "arc_video_accelerator_util.h",
-    "decoder_buffer.cc",
-    "decoder_buffer.h",
     "video_frame_plane.h",
   ]
 
diff --git a/components/arc/video_accelerator/OWNERS b/components/arc/video_accelerator/OWNERS
index 8794119..660cd7c9 100644
--- a/components/arc/video_accelerator/OWNERS
+++ b/components/arc/video_accelerator/OWNERS
@@ -1,3 +1,6 @@
+akahuang@chromium.org
+acourbot@chromium.org
+dstaessens@chromium.org
 hiroh@chromium.org
 kcwu@chromium.org
 posciak@chromium.org
diff --git a/components/arc/video_accelerator/decoder_buffer.cc b/components/arc/video_accelerator/decoder_buffer.cc
deleted file mode 100644
index 9ad9a72..0000000
--- a/components/arc/video_accelerator/decoder_buffer.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/arc/video_accelerator/decoder_buffer.h"
-
-#include "base/logging.h"
-#include "base/memory/platform_shared_memory_region.h"
-#include "base/memory/read_only_shared_memory_region.h"
-#include "base/numerics/checked_math.h"
-#include "base/unguessable_token.h"
-#include "components/arc/video_accelerator/arc_video_accelerator_util.h"
-#include "media/base/decoder_buffer.h"
-#include "media/gpu/buffer_validation.h"
-
-namespace arc {
-
-DecoderBuffer::DecoderBuffer() = default;
-
-DecoderBuffer::DecoderBuffer(base::ScopedFD handle_fd,
-                             uint32_t offset,
-                             uint32_t payload_size,
-                             bool end_of_stream,
-                             base::TimeDelta timestamp)
-    : handle_fd(std::move(handle_fd)),
-      offset(offset),
-      payload_size(payload_size),
-      end_of_stream(end_of_stream),
-      timestamp(timestamp) {}
-
-DecoderBuffer::DecoderBuffer(DecoderBuffer&& buf) = default;
-
-DecoderBuffer& DecoderBuffer::operator=(DecoderBuffer&& buf) = default;
-
-DecoderBuffer::~DecoderBuffer() = default;
-
-scoped_refptr<media::DecoderBuffer> DecoderBuffer::ToMediaDecoderBuffer() && {
-  if (end_of_stream)
-    return media::DecoderBuffer::CreateEOSBuffer();
-
-  base::CheckedNumeric<off_t> checked_offset(offset);
-  base::CheckedNumeric<size_t> checked_payload_size(payload_size);
-  if (!checked_offset.IsValid() || !checked_payload_size.IsValid()) {
-    VLOG(1) << "Overflow when convert offset and payload size to size_t.";
-    return nullptr;
-  }
-
-  size_t required_size;
-  if (!base::CheckAdd<size_t>(offset, payload_size)
-           .AssignIfValid(&required_size)) {
-    VLOG(1) << "Overflow when adding offset and payload size.";
-    return nullptr;
-  }
-
-  size_t file_size = 0;
-  if (!media::GetFileSize(handle_fd.get(), &file_size) ||
-      file_size < required_size) {
-    VLOG(1) << "File size(" << file_size << ") is smaller than required size("
-            << required_size << ").";
-    return nullptr;
-  }
-
-  DCHECK(handle_fd.is_valid());
-  auto readonly_region = base::ReadOnlySharedMemoryRegion::Deserialize(
-      base::subtle::PlatformSharedMemoryRegion::Take(
-          std::move(handle_fd),
-          base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly, file_size,
-          base::UnguessableToken::Create()));
-
-  scoped_refptr<media::DecoderBuffer> output =
-      media::DecoderBuffer::FromSharedMemoryRegion(
-          std::move(readonly_region), checked_offset.ValueOrDie(),
-          checked_payload_size.ValueOrDie());
-  output->set_timestamp(timestamp);
-  return output;
-}
-
-}  // namespace arc
diff --git a/components/arc/video_accelerator/decoder_buffer.h b/components/arc/video_accelerator/decoder_buffer.h
deleted file mode 100644
index aed684b..0000000
--- a/components/arc/video_accelerator/decoder_buffer.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_ARC_VIDEO_ACCELERATOR_DECODER_BUFFER_H_
-#define COMPONENTS_ARC_VIDEO_ACCELERATOR_DECODER_BUFFER_H_
-
-#include "base/files/scoped_file.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/time/time.h"
-
-namespace media {
-class DecoderBuffer;
-}  // namespace media
-
-namespace arc {
-
-// Intermediate class in converting from a mojom::DecoderBuffer to
-// media::DecoderBuffer. Because media::DecoderBuffer doesn't have a public
-// constructor, we cannot convert to media::DecoderBuffer directly by
-// StructTraits::Read().
-struct DecoderBuffer {
-  DecoderBuffer();
-  DecoderBuffer(base::ScopedFD handle_fd,
-                uint32_t offset,
-                uint32_t payload_size,
-                bool end_of_stream,
-                base::TimeDelta timestamp);
-  ~DecoderBuffer();
-  DecoderBuffer(DecoderBuffer&& buf);
-  DecoderBuffer& operator=(DecoderBuffer&& buf);
-
-  // Convert to media::DecoderBuffer.
-  scoped_refptr<media::DecoderBuffer> ToMediaDecoderBuffer() &&;
-
-  // See components/arc/mojom/video_common.mojom for descriptions of each field.
-  base::ScopedFD handle_fd;
-  uint32_t offset;
-  uint32_t payload_size;
-  bool end_of_stream;
-  base::TimeDelta timestamp;
-};
-
-}  // namespace arc
-
-#endif  // COMPONENTS_ARC_VIDEO_ACCELERATOR_DECODER_BUFFER_H_
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 8304eacd..4aa9f56 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -145,6 +145,8 @@
       "toast_surface.cc",
       "toast_surface.h",
       "toast_surface_manager.h",
+      "ui_lock_controller.cc",
+      "ui_lock_controller.h",
       "wm_helper_chromeos.cc",
       "wm_helper_chromeos.h",
       "xdg_shell_surface.cc",
@@ -268,6 +270,7 @@
       "text_input_unittest.cc",
       "toast_surface_unittest.cc",
       "touch_unittest.cc",
+      "ui_lock_controller_unittest.cc",
       "xdg_shell_surface_unittest.cc",
     ]
 
diff --git a/components/exo/seat.cc b/components/exo/seat.cc
index d161932..3c54220 100644
--- a/components/exo/seat.cc
+++ b/components/exo/seat.cc
@@ -59,6 +59,9 @@
   // null. https://crbug.com/856230
   if (ui::PlatformEventSource::GetInstance())
     ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
+#if defined(OS_CHROMEOS)
+  ui_lock_controller_ = std::make_unique<UILockController>(this);
+#endif
 }
 
 Seat::~Seat() {
diff --git a/components/exo/seat.h b/components/exo/seat.h
index 9f99c2e..e752f5c 100644
--- a/components/exo/seat.h
+++ b/components/exo/seat.h
@@ -19,6 +19,10 @@
 #include "ui/events/keycodes/dom/dom_codes.h"
 #include "ui/events/platform/platform_event_observer.h"
 
+#if defined(OS_CHROMEOS)
+#include "components/exo/ui_lock_controller.h"
+#endif
+
 namespace ui {
 enum class DomCode;
 class KeyEvent;
@@ -159,6 +163,10 @@
 
   gfx::Point last_location_;
 
+#if defined(OS_CHROMEOS)
+  std::unique_ptr<UILockController> ui_lock_controller_;
+#endif  // defined(OS_CHROMEOS)
+
   base::WeakPtrFactory<Seat> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(Seat);
diff --git a/components/exo/test/exo_test_base.h b/components/exo/test/exo_test_base.h
index 6461e57..7a651d4e 100644
--- a/components/exo/test/exo_test_base.h
+++ b/components/exo/test/exo_test_base.h
@@ -25,6 +25,13 @@
 class ExoTestBase : public ash::AshTestBase {
  public:
   ExoTestBase();
+
+  // Constructs an ExoTestBase with |traits| being forwarded to its
+  // TaskEnvironment. See the corresponding |AshTestBase| constructor.
+  template <typename... TaskEnvironmentTraits>
+  NOINLINE explicit ExoTestBase(TaskEnvironmentTraits&&... traits)
+      : AshTestBase(std::forward<TaskEnvironmentTraits>(traits)...) {}
+
   ~ExoTestBase() override;
 
   // TODO(oshima): Convert unit tests to use this.
diff --git a/components/exo/ui_lock_controller.cc b/components/exo/ui_lock_controller.cc
new file mode 100644
index 0000000..ef4a1605
--- /dev/null
+++ b/components/exo/ui_lock_controller.cc
@@ -0,0 +1,123 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/ui_lock_controller.h"
+
+#include "ash/public/cpp/app_types.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/wm/window_state.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "components/exo/seat.h"
+#include "components/exo/shell_surface_util.h"
+#include "components/exo/surface.h"
+#include "components/exo/wm_helper.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
+#include "ui/events/event_constants.h"
+#include "ui/events/keycodes/dom/dom_code.h"
+#include "ui/views/widget/widget.h"
+
+namespace exo {
+
+constexpr auto kLongPressEscapeDuration = base::TimeDelta::FromSeconds(2);
+constexpr auto kExcludedFlags = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
+                                ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN |
+                                ui::EF_ALTGR_DOWN | ui::EF_IS_REPEAT;
+
+UILockController::UILockController(Seat* seat) : seat_(seat) {
+  WMHelper::GetInstance()->AddPreTargetHandler(this);
+  seat_->AddObserver(this);
+}
+
+UILockController::~UILockController() {
+  seat_->RemoveObserver(this);
+  WMHelper::GetInstance()->RemovePreTargetHandler(this);
+}
+
+void UILockController::OnKeyEvent(ui::KeyEvent* event) {
+  // If the event target is not an exo::Surface, let another handler process the
+  // event.
+  if (!GetShellMainSurface(static_cast<aura::Window*>(event->target())) &&
+      !Surface::AsSurface(static_cast<aura::Window*>(event->target()))) {
+    return;
+  }
+
+  if (event->code() == ui::DomCode::ESCAPE &&
+      (event->flags() & kExcludedFlags) == 0) {
+    OnEscapeKey(event->type() == ui::ET_KEY_PRESSED);
+  }
+}
+
+void UILockController::OnSurfaceFocused(Surface* gained_focus) {
+  if (gained_focus != focused_surface_to_unlock_)
+    StopTimer();
+}
+
+namespace {
+bool FocusedWindowIsNonImmersiveFullscreen(Seat* seat) {
+  auto* surface = seat->GetFocusedSurface();
+  if (!surface)
+    return false;
+
+  auto* widget =
+      views::Widget::GetTopLevelWidgetForNativeView(surface->window());
+  if (!widget)
+    return false;
+
+  aura::Window* window = widget->GetNativeWindow();
+  if (!window || window->GetProperty(ash::kImmersiveImpliedByFullscreen))
+    return false;
+
+  // TODO(b/165865831): Add the Borealis AppType if/when we add one.
+  if (window->GetProperty(aura::client::kAppType) !=
+      static_cast<int>(ash::AppType::CROSTINI_APP)) {
+    return false;
+  }
+
+  auto* window_state = ash::WindowState::Get(window);
+  return window_state && window_state->IsFullscreen();
+}
+}  // namespace
+
+void UILockController::OnEscapeKey(bool pressed) {
+  if (pressed) {
+    if (FocusedWindowIsNonImmersiveFullscreen(seat_) &&
+        !exit_fullscreen_timer_.IsRunning()) {
+      focused_surface_to_unlock_ = seat_->GetFocusedSurface();
+      exit_fullscreen_timer_.Start(
+          FROM_HERE, kLongPressEscapeDuration,
+          base::BindOnce(&UILockController::OnEscapeHeld,
+                         base::Unretained(this)));
+    }
+  } else {
+    StopTimer();
+  }
+}
+
+void UILockController::OnEscapeHeld() {
+  auto* surface = seat_->GetFocusedSurface();
+  if (!surface || surface != focused_surface_to_unlock_) {
+    focused_surface_to_unlock_ = nullptr;
+    return;
+  }
+
+  focused_surface_to_unlock_ = nullptr;
+
+  auto* widget =
+      views::Widget::GetTopLevelWidgetForNativeView(surface->window());
+  auto* window_state =
+      ash::WindowState::Get(widget ? widget->GetNativeWindow() : nullptr);
+  if (window_state)
+    window_state->Minimize();
+}
+
+void UILockController::StopTimer() {
+  if (exit_fullscreen_timer_.IsRunning()) {
+    exit_fullscreen_timer_.Stop();
+    focused_surface_to_unlock_ = nullptr;
+  }
+}
+
+}  // namespace exo
diff --git a/components/exo/ui_lock_controller.h b/components/exo/ui_lock_controller.h
new file mode 100644
index 0000000..fe84badc1
--- /dev/null
+++ b/components/exo/ui_lock_controller.h
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_EXO_UI_LOCK_CONTROLLER_H_
+#define COMPONENTS_EXO_UI_LOCK_CONTROLLER_H_
+
+#include "base/timer/timer.h"
+#include "components/exo/seat_observer.h"
+#include "ui/events/event_handler.h"
+
+namespace exo {
+
+class Seat;
+
+extern const base::TimeDelta kLongPressEscapeDuration;
+
+// Listens for long presses on the Escape key, which breaks out of various
+// kinds of "locks" that a window may hold.
+//
+// TODO(cpelling): For now this is just non-immersive fullscreen. Eventually
+// this should also break pointer lock.
+//
+// The "long keypress" design is inspired by Chromium's Keyboard Lock feature
+// (see https://chromestatus.com/feature/5642959835889664).
+class UILockController : public ui::EventHandler, public SeatObserver {
+ public:
+  explicit UILockController(Seat* seat);
+  UILockController(const UILockController&) = delete;
+  UILockController& operator=(const UILockController&) = delete;
+  ~UILockController() override;
+
+  // Overridden from ui::EventHandler:
+  void OnKeyEvent(ui::KeyEvent* event) override;
+
+  // Overridden from SeatObserver:
+  void OnSurfaceFocusing(Surface* gaining_focus) override {}
+  void OnSurfaceFocused(Surface* gained_focus) override;
+
+ private:
+  void OnEscapeKey(bool pressed);
+  void OnEscapeHeld();
+  void StopTimer();
+
+  Seat* seat_;
+  base::OneShotTimer exit_fullscreen_timer_;
+
+  // The surface which was focused when |exit_fullscreen_timer_| started
+  // running, or nullptr if the timer isn't running. Do not dereference; may
+  // dangle if the Surface is destroyed while the timer is running. Valid only
+  // for comparison purposes.
+  Surface* focused_surface_to_unlock_ = nullptr;
+};
+
+}  // namespace exo
+
+#endif  // COMPONENTS_EXO_UI_LOCK_CONTROLLER_H_
diff --git a/components/exo/ui_lock_controller_unittest.cc b/components/exo/ui_lock_controller_unittest.cc
new file mode 100644
index 0000000..59401ca7
--- /dev/null
+++ b/components/exo/ui_lock_controller_unittest.cc
@@ -0,0 +1,239 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/exo/ui_lock_controller.h"
+
+#include "ash/public/cpp/app_types.h"
+#include "ash/shell.h"
+#include "ash/wm/window_state.h"
+#include "components/exo/buffer.h"
+#include "components/exo/display.h"
+#include "components/exo/shell_surface.h"
+#include "components/exo/surface.h"
+#include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/exo_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/wm/core/window_util.h"
+
+namespace exo {
+namespace {
+
+struct SurfaceTriplet {
+  std::unique_ptr<Surface> surface;
+  std::unique_ptr<ShellSurface> shell_surface;
+  std::unique_ptr<Buffer> buffer;
+
+  aura::Window* GetTopLevelWindow() {
+    auto* top_level_widget = views::Widget::GetTopLevelWidgetForNativeView(
+        shell_surface->host_window());
+    assert(top_level_widget);
+    return top_level_widget->GetNativeWindow();
+  }
+
+  ash::WindowState* GetTopLevelWindowState() {
+    return ash::WindowState::Get(GetTopLevelWindow());
+  }
+};
+
+class UILockControllerTest : public test::ExoTestBase {
+ public:
+  UILockControllerTest()
+      : test::ExoTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
+  ~UILockControllerTest() override = default;
+
+  UILockControllerTest(const UILockControllerTest&) = delete;
+  UILockControllerTest& operator=(const UILockControllerTest&) = delete;
+
+ protected:
+  // test::ExoTestBase:
+  void SetUp() override {
+    test::ExoTestBase::SetUp();
+    seat_ = std::make_unique<Seat>();
+  }
+
+  void TearDown() override {
+    seat_.reset();
+    test::ExoTestBase::TearDown();
+  }
+
+  SurfaceTriplet BuildSurface(int w, int h) {
+    auto surface = std::make_unique<Surface>();
+    auto shell_surface = std::make_unique<ShellSurface>(
+        surface.get(), gfx::Point{0, 0},
+        /*activatable=*/true,
+        /*can_minimize=*/true, ash::desks_util::GetActiveDeskContainerId());
+    auto buffer = std::make_unique<Buffer>(
+        exo_test_helper()->CreateGpuMemoryBuffer({w, h}));
+    surface->Attach(buffer.get());
+
+    return {std::move(surface), std::move(shell_surface), std::move(buffer)};
+  }
+
+  std::unique_ptr<Seat> seat_;
+};
+
+void SetAppType(SurfaceTriplet& surface, ash::AppType appType) {
+  surface.GetTopLevelWindow()->SetProperty(aura::client::kAppType,
+                                           static_cast<int>(appType));
+}
+
+TEST_F(UILockControllerTest, HoldingEscapeExitsFullscreen) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface.shell_surface->SetFullscreen(true);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+  EXPECT_TRUE(window_state->IsFullscreen());
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  EXPECT_TRUE(window_state->IsFullscreen());  // no change yet
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  EXPECT_FALSE(window_state->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, HoldingCtrlEscapeDoesNotExitFullscreen) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface.shell_surface->SetFullscreen(true);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+  EXPECT_TRUE(window_state->IsFullscreen());
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_CONTROL_DOWN);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+  EXPECT_TRUE(window_state->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, HoldingEscapeOnlyAffectsCrostiniApps) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface.shell_surface->SetFullscreen(true);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::ARC_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+  EXPECT_TRUE(window_state->IsFullscreen());
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+  EXPECT_TRUE(window_state->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, HoldingEscapeOnlyExitsFocusedFullscreen) {
+  SurfaceTriplet test_surface1 = BuildSurface(1024, 768);
+  test_surface1.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface1.shell_surface->SetFullscreen(true);
+  test_surface1.surface->Commit();
+  SetAppType(test_surface1, ash::AppType::CROSTINI_APP);
+
+  SurfaceTriplet test_surface2 = BuildSurface(1024, 768);
+  test_surface2.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface2.shell_surface->SetFullscreen(true);
+  test_surface2.surface->Commit();
+  SetAppType(test_surface2, ash::AppType::CROSTINI_APP);
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+  EXPECT_TRUE(test_surface1.GetTopLevelWindowState()->IsFullscreen());
+  EXPECT_FALSE(test_surface2.GetTopLevelWindowState()->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, DestroyingWindowCancels) {
+  std::unique_ptr<SurfaceTriplet> test_surface =
+      std::make_unique<SurfaceTriplet>(BuildSurface(1024, 768));
+  test_surface->shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface->shell_surface->SetFullscreen(true);
+  test_surface->surface->Commit();
+  SetAppType(*test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface->GetTopLevelWindowState();
+  EXPECT_TRUE(window_state->IsFullscreen());
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  test_surface.reset();  // Destroying the Surface destroys the Window
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(3));
+
+  // The implicit assertion is that the code doesn't crash.
+}
+
+TEST_F(UILockControllerTest, FocusChangeCancels) {
+  // Arrange: two windows, one is fullscreen and focused
+  SurfaceTriplet other_surface = BuildSurface(1024, 768);
+  other_surface.surface->Commit();
+  SetAppType(other_surface, ash::AppType::CROSTINI_APP);
+
+  SurfaceTriplet fullscreen_surface = BuildSurface(1024, 768);
+  fullscreen_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  fullscreen_surface.shell_surface->SetFullscreen(true);
+  fullscreen_surface.surface->Commit();
+  SetAppType(fullscreen_surface, ash::AppType::CROSTINI_APP);
+
+  EXPECT_EQ(fullscreen_surface.surface.get(), seat_->GetFocusedSurface());
+  EXPECT_FALSE(fullscreen_surface.GetTopLevelWindowState()->IsMinimized());
+
+  // Act: Press escape, then toggle focus back and forth
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  wm::ActivateWindow(other_surface.surface->window());
+  wm::ActivateWindow(fullscreen_surface.surface->window());
+
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+  // Assert: Fullscreen window was not minimized, despite regaining focus.
+  EXPECT_FALSE(fullscreen_surface.GetTopLevelWindowState()->IsMinimized());
+  EXPECT_EQ(fullscreen_surface.surface.get(), seat_->GetFocusedSurface());
+}
+
+TEST_F(UILockControllerTest, EscapeDoesNotExitImmersiveFullscreen) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetFullscreen(true);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+  EXPECT_TRUE(window_state->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, ShortHoldEscapeDoesNotExitFullscreen) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface.shell_surface->SetFullscreen(true);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(1));
+  GetEventGenerator()->ReleaseKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+  EXPECT_TRUE(window_state->IsFullscreen());
+}
+
+TEST_F(UILockControllerTest, HoldingEscapeDoesNotMinimizeIfWindowed) {
+  SurfaceTriplet test_surface = BuildSurface(1024, 768);
+  test_surface.shell_surface->SetUseImmersiveForFullscreen(false);
+  test_surface.surface->Commit();
+  SetAppType(test_surface, ash::AppType::CROSTINI_APP);
+  auto* window_state = test_surface.GetTopLevelWindowState();
+
+  GetEventGenerator()->PressKey(ui::VKEY_ESCAPE, ui::EF_NONE);
+  task_environment()->FastForwardBy(base::TimeDelta::FromSeconds(2));
+
+  EXPECT_FALSE(window_state->IsMinimized());
+}
+
+}  // namespace
+}  // namespace exo
diff --git a/components/exo/wayland/wl_seat.h b/components/exo/wayland/wl_seat.h
index 84e2b98..adf4452d 100644
--- a/components/exo/wayland/wl_seat.h
+++ b/components/exo/wayland/wl_seat.h
@@ -22,14 +22,14 @@
 struct WaylandSeat {
   WaylandSeat(Seat* seat, SerialTracker* serial_tracker)
       : seat(seat), serial_tracker(serial_tracker) {}
+  WaylandSeat(const WaylandSeat&) = delete;
+  WaylandSeat& operator=(const WaylandSeat&) = delete;
 
   // Owned by Display, which always outlives wl_seat.
   Seat* const seat;
 
   // Owned by Server, which always outlives wl_seat.
   SerialTracker* const serial_tracker;
-
-  DISALLOW_COPY_AND_ASSIGN(WaylandSeat);
 };
 
 void bind_seat(wl_client* client, void* data, uint32_t version, uint32_t id);
diff --git a/components/optimization_guide/hints_processing_util.cc b/components/optimization_guide/hints_processing_util.cc
index 8dce8af..c96476da 100644
--- a/components/optimization_guide/hints_processing_util.cc
+++ b/components/optimization_guide/hints_processing_util.cc
@@ -47,6 +47,8 @@
       return "FastHostHints";
     case proto::OptimizationType::DELAY_ASYNC_SCRIPT_EXECUTION:
       return "DelayAsyncScriptExecution";
+    case proto::OptimizationType::LITE_VIDEO:
+      return "LiteVideo";
   }
   NOTREACHED();
   return std::string();
diff --git a/components/optimization_guide/proto/BUILD.gn b/components/optimization_guide/proto/BUILD.gn
index 9f305010..8dbebbb 100644
--- a/components/optimization_guide/proto/BUILD.gn
+++ b/components/optimization_guide/proto/BUILD.gn
@@ -14,6 +14,7 @@
     "delay_async_script_execution_metadata.proto",
     "hint_cache.proto",
     "hints.proto",
+    "lite_video_metadata.proto",
     "loading_predictor_metadata.proto",
     "models.proto",
     "performance_hints_metadata.proto",
@@ -29,6 +30,7 @@
       "common_types.proto",
       "delay_async_script_execution_metadata.proto",
       "hints.proto",
+      "lite_video_metadata.proto",
       "loading_predictor_metadata.proto",
       "models.proto",
       "performance_hints_metadata.proto",
diff --git a/components/optimization_guide/proto/common_types.proto b/components/optimization_guide/proto/common_types.proto
index 4716d0f5..f0dbf02 100644
--- a/components/optimization_guide/proto/common_types.proto
+++ b/components/optimization_guide/proto/common_types.proto
@@ -56,3 +56,24 @@
   // The hash of the active group within the field trial.
   optional uint32 group_hash = 2;
 }
+
+// A Duration represents a signed, fixed-length span of time represented
+// as a count of seconds and fractions of seconds at nanosecond
+// resolution. It is independent of any calendar and concepts like "day"
+// or "month". It is related to Timestamp in that the difference between
+// two Timestamp values is a Duration and it can be added or subtracted
+// from a Timestamp. Range is approximately +-10,000 years.
+// This is local definition matching server side duration.proto definition.
+message Duration {
+  // Signed seconds of the span of time. Must be from -315,576,000,000
+  // to +315,576,000,000 inclusive.
+  optional int64 seconds = 1;
+
+  // Signed fractions of a second at nanosecond resolution of the span
+  // of time. Durations less than one second are represented with a 0
+  // `seconds` field and a positive or negative `nanos` field. For durations
+  // of one second or more, a non-zero value for the `nanos` field must be
+  // of the same sign as the `seconds` field. Must be from -999,999,999
+  // to +999,999,999 inclusive.
+  optional int32 nanos = 2;
+}
diff --git a/components/optimization_guide/proto/hints.proto b/components/optimization_guide/proto/hints.proto
index 81a41a6a..9d68910e 100644
--- a/components/optimization_guide/proto/hints.proto
+++ b/components/optimization_guide/proto/hints.proto
@@ -93,27 +93,6 @@
   repeated MatchedHintInfo hints_to_remove = 3;
 }
 
-// A Duration represents a signed, fixed-length span of time represented
-// as a count of seconds and fractions of seconds at nanosecond
-// resolution. It is independent of any calendar and concepts like "day"
-// or "month". It is related to Timestamp in that the difference between
-// two Timestamp values is a Duration and it can be added or subtracted
-// from a Timestamp. Range is approximately +-10,000 years.
-// This is local definition matching server side duration.proto definition.
-message Duration {
-  // Signed seconds of the span of time. Must be from -315,576,000,000
-  // to +315,576,000,000 inclusive.
-  optional int64 seconds = 1;
-
-  // Signed fractions of a second at nanosecond resolution of the span
-  // of time. Durations less than one second are represented with a 0
-  // `seconds` field and a positive or negative `nanos` field. For durations
-  // of one second or more, a non-zero value for the `nanos` field must be
-  // of the same sign as the `seconds` field. Must be from -999,999,999
-  // to +999,999,999 inclusive.
-  optional int32 nanos = 2;
-}
-
 
 enum OptimizationType {
   TYPE_UNSPECIFIED = 0;
@@ -146,6 +125,12 @@
   // This optimization provides information about the effective delay for async
   // script execution.
   DELAY_ASYNC_SCRIPT_EXECUTION = 11;
+  // TODO(crbug/1112515): Add type here for delay low priority resources to
+  // match server.
+  //
+  // This optimization provides information about how to throttle meda requests
+  // to reduce the bitrate of adaptively streamed media.
+  LITE_VIDEO = 13;
 }
 
 // Presents semantics for how page load URLs should be matched.
diff --git a/components/optimization_guide/proto/lite_video_metadata.proto b/components/optimization_guide/proto/lite_video_metadata.proto
new file mode 100644
index 0000000..490d3c0
--- /dev/null
+++ b/components/optimization_guide/proto/lite_video_metadata.proto
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_package = "org.chromium.components.optimization_guide.proto";
+option java_outer_classname = "LiteVideoMetadataProto";
+
+package optimization_guide.proto;
+
+import "common_types.proto";
+
+message LiteVideoHint {
+  // The target video resolution for throttling. Initially unused.
+  optional int64 target_video_resolution = 1;
+  // The network downlink bandwidth target in kilobits per second used to
+  // calculate the throttling delay on media requests.
+  optional int64 target_downlink_bandwidth_kbps = 2;
+  // The network downlink rtt target latency used to calculate the
+  // throttling delay on media requests.
+  optional Duration target_downlink_rtt_latency = 3;
+  // The number of kilobytes for media to be observed before starting to
+  // throttle requests.
+  optional int64 kilobytes_to_buffer_before_throttle = 4;
+  // The maximum delay a throttle can introduce for a media request in
+  // milliseconds.
+  optional Duration max_throttling_delay = 5;
+}
+
+// Optimization metadata associated with LiteVideos.
+//
+// This is only populated for the LITE_VIDEO optimization type.
+message LiteVideoMetadata {
+  // A LiteVideo hint.
+  optional LiteVideoHint lite_video_hint = 1;
+}
\ No newline at end of file
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 6fa3897..543feb3 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -17579,7 +17579,7 @@
       'owners': ['bdea@chromium.org', 'nparker@chromium.org'],
       'type': 'main',
       'schema': { 'type': 'boolean' },
-      'supported_on': ['chrome.*:66-', 'chrome_os:66-'],
+      'supported_on': ['chrome.*:66-', 'chrome_os:66-', 'android: 87-'],
       'features': {
         'dynamic_refresh': True,
         'per_profile': True,
@@ -17595,6 +17595,7 @@
       If you set this policy, users can't change it. If not set, users can decide whether to send reports or not.
 
       See more about Safe Browsing ( https://developers.google.com/safe-browsing ).''',
+      'arc_support': 'This policy is not supported within Arc.',
     },
     {
       'name': 'MachineLevelUserCloudPolicyEnrollmentToken',
diff --git a/components/printing/common/cloud_print_cdd_conversion.cc b/components/printing/common/cloud_print_cdd_conversion.cc
index 25c9b7c..42fa683 100644
--- a/components/printing/common/cloud_print_cdd_conversion.cc
+++ b/components/printing/common/cloud_print_cdd_conversion.cc
@@ -44,15 +44,15 @@
 
 #if defined(OS_CHROMEOS)
 printer::TypedValueVendorCapability::ValueType ToCloudValueType(
-    base::Value::Type type) {
+    printing::AdvancedCapability::Type type) {
   switch (type) {
-    case base::Value::Type::BOOLEAN:
+    case printing::AdvancedCapability::Type::kBoolean:
       return printer::TypedValueVendorCapability::ValueType::BOOLEAN;
-    case base::Value::Type::DOUBLE:
+    case printing::AdvancedCapability::Type::kFloat:
       return printer::TypedValueVendorCapability::ValueType::FLOAT;
-    case base::Value::Type::INTEGER:
+    case printing::AdvancedCapability::Type::kInteger:
       return printer::TypedValueVendorCapability::ValueType::INTEGER;
-    case base::Value::Type::STRING:
+    case printing::AdvancedCapability::Type::kString:
       return printer::TypedValueVendorCapability::ValueType::STRING;
     default:
       NOTREACHED();
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 819423c..5c89693c 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -481,6 +481,11 @@
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
+                       AccessibilityEventsChildrenChangedOnlyOnAncestor) {
+  RunEventTest(FILE_PATH_LITERAL("children-changed-only-on-ancestor.html"));
+}
+
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityEventsTest,
                        AccessibilityEventsCheckedStateChanged) {
   RunEventTest(FILE_PATH_LITERAL("checked-state-changed.html"));
 }
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 39db8b7f..44973b1 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -269,6 +269,13 @@
     return;
   }
 
+  auto new_origin = url::Origin::Create(navigation_handle->GetURL());
+  if (navigation_handle->IsInMainFrame() &&
+      !new_origin.IsSameOriginWith(origin_)) {
+    audio_device_id_for_origin_.reset();
+    origin_ = new_origin;
+  }
+
   RenderFrameHost* rfh = navigation_handle->GetRenderFrameHost();
   if (services_.count(rfh))
     services_[rfh]->DidFinishNavigation();
@@ -351,6 +358,8 @@
     return AddPepperPlayer(observer, player_id);
 
   observer->OnSetVolumeMultiplier(player_id, GetVolumeMultiplier());
+  if (audio_device_id_for_origin_)
+    observer->OnSetAudioSinkId(player_id, audio_device_id_for_origin_.value());
 
   AudioFocusType required_audio_focus_type;
   if (media_content_type == media::MediaContentType::Persistent)
@@ -1079,6 +1088,8 @@
 }
 
 void MediaSessionImpl::SetAudioSinkId(const base::Optional<std::string>& id) {
+  audio_device_id_for_origin_ = id;
+
   for (const auto& it : normal_players_) {
     it.first.observer->OnSetAudioSinkId(
         it.first.player_id,
@@ -1366,6 +1377,11 @@
 }
 
 void MediaSessionImpl::OnAudioOutputSinkIdChanged() {
+  if (audio_device_id_for_origin_ &&
+      audio_device_id_for_origin_ != GetSharedAudioOutputDeviceId()) {
+    audio_device_id_for_origin_.reset();
+  }
+
   RebuildAndNotifyMediaSessionInfoChanged();
 }
 
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 35c69ed..daa6d10 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -255,6 +255,10 @@
 
   // Routes the audio from this Media Session to the given output device. If
   // |id| is null, we will route to the default output device.
+  // Players created after this setting has been set will also have their audio
+  // rerouted. This setting persists until cross-origin navigation occurs, the
+  // renderer reports an audio sink change to a device different from |id|, or
+  // this method is called again.
   void SetAudioSinkId(const base::Optional<std::string>& id) override;
 
   // Downloads the bitmap version of a MediaImage at least |minimum_size_px|
@@ -452,6 +456,11 @@
   // True if the WebContents associated with this MediaSessionImpl is focused.
   bool focused_ = false;
 
+  // Used to persist audio device selection between navigations on the same
+  // origin.
+  url::Origin origin_;
+  base::Optional<std::string> audio_device_id_for_origin_;
+
 #if defined(OS_ANDROID)
   std::unique_ptr<MediaSessionAndroid> session_android_;
 #endif  // defined(OS_ANDROID)
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index 00d65e8..2030461a 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -2886,4 +2886,52 @@
   }
 }
 
+IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
+                       AudioDeviceSettingPersists) {
+  // When an audio output device has been set: in addition to players switching
+  // to that audio device, players created later on the same origin in the same
+  // session should also use that device.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title1.html")));
+
+  auto player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
+  int player_1 = player_observer->StartNewPlayer();
+  AddPlayer(player_observer.get(), player_1,
+            media::MediaContentType::Persistent);
+  UISetAudioSink("speaker1");
+  EXPECT_EQ(player_observer->GetAudioOutputSinkId(player_1), "speaker1");
+
+  // When a second player has been added on the same page, it should use the
+  // audio device previously set.
+  int player_2 = player_observer->StartNewPlayer();
+  AddPlayer(player_observer.get(), player_2,
+            media::MediaContentType::Persistent);
+  EXPECT_EQ(player_observer->GetAudioOutputSinkId(player_2), "speaker1");
+
+  // Clear the players and navigate to a new page on the same origin.
+  RemovePlayers(player_observer.get());
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("a.com", "/title2.html")));
+  player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
+
+  // After navigating to another page on the same origin, newly created players
+  // should use the previously set device.
+  player_1 = player_observer->StartNewPlayer();
+  AddPlayer(player_observer.get(), player_1,
+            media::MediaContentType::Persistent);
+  EXPECT_EQ(player_observer->GetAudioOutputSinkId(player_1), "speaker1");
+
+  // Clear the players and navigate to a new page on a different origin
+  RemovePlayers(player_observer.get());
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title1.html")));
+  player_observer = std::make_unique<MockMediaSessionPlayerObserver>();
+
+  // After navigating to another page on a different origin, newly created
+  // players should not use the previously set device.
+  player_1 = player_observer->StartNewPlayer();
+  AddPlayer(player_observer.get(), player_1,
+            media::MediaContentType::Persistent);
+  EXPECT_NE(player_observer->GetAudioOutputSinkId(player_1), "speaker1");
+}
 }  // namespace content
diff --git a/content/browser/media/session/mock_media_session_player_observer.cc b/content/browser/media/session/mock_media_session_player_observer.cc
index ccf7e214..f689b30e 100644
--- a/content/browser/media/session/mock_media_session_player_observer.cc
+++ b/content/browser/media/session/mock_media_session_player_observer.cc
@@ -76,7 +76,7 @@
     int player_id,
     const std::string& raw_device_id) {
   EXPECT_GE(player_id, 0);
-  EXPECT_EQ(players_.size(), 1u);
+  EXPECT_GT(players_.size(), static_cast<size_t>(player_id));
 
   ++received_set_audio_sink_id_calls_;
   players_[player_id].audio_sink_id_ = raw_device_id;
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 2363bb6..1ae1a6b 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -556,7 +556,8 @@
 // as a last resort.
 void SetCustomizedRuntimeFeaturesFromCombinedArgs(
     const base::CommandLine& command_line,
-    bool enable_experimental_web_platform_features) {
+    bool enable_experimental_web_platform_features,
+    bool enable_blink_test_features) {
   // CAUTION: Only add custom enabling logic here if it cannot
   // be covered by the other functions.
 
@@ -605,6 +606,10 @@
     WebRuntimeFeatures::EnableNetInfoDownlinkMax(true);
   }
 
+  if (enable_blink_test_features) {
+    WebRuntimeFeatures::EnableSubresourceWebBundles(true);
+  }
+
   // Except for stable release mode, web tests still run with Web Components
   // v0 features enabled.
   // TODO(crbug.com/937746): remove this once the features are deleted.
@@ -672,8 +677,10 @@
   // Sets experimental features.
   bool enable_experimental_web_platform_features =
       command_line.HasSwitch(switches::kEnableExperimentalWebPlatformFeatures);
+  bool enable_blink_test_features =
+      command_line.HasSwitch(switches::kEnableBlinkTestFeatures);
 
-  if (command_line.HasSwitch(switches::kEnableBlinkTestFeatures)) {
+  if (enable_blink_test_features) {
     enable_experimental_web_platform_features = true;
     WebRuntimeFeatures::EnableTestOnlyFeatures(true);
   }
@@ -705,7 +712,8 @@
   SetRuntimeFeaturesFromFieldTrialParams();
 
   SetCustomizedRuntimeFeaturesFromCombinedArgs(
-      command_line, enable_experimental_web_platform_features);
+      command_line, enable_experimental_web_platform_features,
+      enable_blink_test_features);
 
   // Enable explicitly enabled features, and then disable explicitly disabled
   // ones.
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 36bf3fd..b9a31f8 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -914,8 +914,6 @@
 const char kWebXrRuntimeOrientationSensors[] = "orientation-sensors";
 
 // The following are the runtimes that WebXr supports.
-const char kWebXrRuntimeOculus[] = "oculus";
-const char kWebXrRuntimeOpenVr[] = "openvr";
 const char kWebXrRuntimeOpenXr[] = "openxr";
 const char kWebXrRuntimeWMR[] = "windows-mixed-reality";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 2e622669..73904de2 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -248,8 +248,6 @@
 CONTENT_EXPORT extern const char kWebXrForceRuntime[];
 CONTENT_EXPORT extern const char kWebXrRuntimeNone[];
 CONTENT_EXPORT extern const char kWebXrRuntimeOrientationSensors[];
-CONTENT_EXPORT extern const char kWebXrRuntimeOculus[];
-CONTENT_EXPORT extern const char kWebXrRuntimeOpenVr[];
 CONTENT_EXPORT extern const char kWebXrRuntimeOpenXr[];
 CONTENT_EXPORT extern const char kWebXrRuntimeWMR[];
 
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 52fd7fcc..e71a1b5 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/gtest_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "content/common/frame_messages.h"
@@ -23,6 +24,7 @@
 #include "content/common/renderer.mojom.h"
 #include "content/common/unfreezable_frame_messages.h"
 #include "content/common/widget_messages.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/document_state.h"
@@ -872,8 +874,16 @@
 
 class RenderFrameRemoteInterfacesTest : public RenderViewTest {
  public:
-  RenderFrameRemoteInterfacesTest() {}
-  ~RenderFrameRemoteInterfacesTest() override {}
+  RenderFrameRemoteInterfacesTest() {
+    scoped_feature_list_.InitAndEnableFeature(
+        features::kAllowContentInitiatedDataUrlNavigations);
+    blink::WebRuntimeFeatures::EnableFeatureFromString(
+        "AllowContentInitiatedDataUrlNavigations", true);
+  }
+  ~RenderFrameRemoteInterfacesTest() override {
+    blink::WebRuntimeFeatures::EnableFeatureFromString(
+        "AllowContentInitiatedDataUrlNavigations", false);
+  }
 
  protected:
   void SetUp() override {
@@ -907,6 +917,7 @@
  private:
   // Owned by RenderViewTest.
   FrameCreationObservingRendererClient* frame_creation_observer_ = nullptr;
+  base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderFrameRemoteInterfacesTest);
 };
diff --git a/content/services/isolated_xr_device/xr_runtime_provider.cc b/content/services/isolated_xr_device/xr_runtime_provider.cc
index e6c72ba1..0939a57 100644
--- a/content/services/isolated_xr_device/xr_runtime_provider.cc
+++ b/content/services/isolated_xr_device/xr_runtime_provider.cc
@@ -12,14 +12,6 @@
 #include "device/base/features.h"
 #include "device/vr/buildflags/buildflags.h"
 
-#if BUILDFLAG(ENABLE_OPENVR)
-#include "device/vr/openvr/openvr_device.h"
-#endif
-
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-#include "device/vr/oculus/oculus_device.h"
-#endif
-
 #if BUILDFLAG(ENABLE_WINDOWS_MR)
 #include "device/vr/windows_mixed_reality/mixed_reality_device.h"
 #include "device/vr/windows_mixed_reality/mixed_reality_statics.h"
@@ -128,24 +120,6 @@
   }
 #endif
 
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-  if (!preferred_device_enabled && IsOculusVrHardwareAvailable()) {
-    SetOculusVrRuntimeStatus(RuntimeStatus::kEnable);
-    preferred_device_enabled = true;
-  } else {
-    SetOculusVrRuntimeStatus(RuntimeStatus::kDisable);
-  }
-#endif
-
-#if BUILDFLAG(ENABLE_OPENVR)
-  if (!preferred_device_enabled && IsOpenVrHardwareAvailable()) {
-    SetOpenVrRuntimeStatus(RuntimeStatus::kEnable);
-    preferred_device_enabled = true;
-  } else {
-    SetOpenVrRuntimeStatus(RuntimeStatus::kDisable);
-  }
-#endif
-
   // Schedule this function to run again later.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
@@ -162,22 +136,6 @@
   // we'll get an error for 'command_line' being unused.
   ALLOW_UNUSED_LOCAL(command_line);
 
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-  if (IsEnabled(command_line, device::features::kOculusVR,
-                switches::kWebXrRuntimeOculus)) {
-    should_check_oculus_ = device::OculusDevice::IsApiAvailable();
-    any_runtimes_available |= should_check_oculus_;
-  }
-#endif
-
-#if BUILDFLAG(ENABLE_OPENVR)
-  if (IsEnabled(command_line, device::features::kOpenVR,
-                switches::kWebXrRuntimeOpenVr)) {
-    should_check_openvr_ = device::OpenVRDevice::IsApiAvailable();
-    any_runtimes_available |= should_check_openvr_;
-  }
-#endif
-
 #if BUILDFLAG(ENABLE_WINDOWS_MR)
   if (IsEnabled(command_line, device::features::kWindowsMixedReality,
                 switches::kWebXrRuntimeWMR)) {
@@ -211,34 +169,6 @@
   client_->OnDevicesEnumerated();
 }
 
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-bool IsolatedXRRuntimeProvider::IsOculusVrHardwareAvailable() {
-  return should_check_oculus_ &&
-         ((oculus_device_ && oculus_device_->IsAvailable()) ||
-          device::OculusDevice::IsHwAvailable());
-}
-
-void IsolatedXRRuntimeProvider::SetOculusVrRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_.get(), status,
-                   base::BindOnce(&CreateDevice<device::OculusDevice>),
-                   &oculus_device_);
-}
-#endif  // BUILDFLAG(ENABLE_OCULUS_VR)
-
-#if BUILDFLAG(ENABLE_OPENVR)
-bool IsolatedXRRuntimeProvider::IsOpenVrHardwareAvailable() {
-  return should_check_openvr_ &&
-         ((openvr_device_ && openvr_device_->IsAvailable()) ||
-          device::OpenVRDevice::IsHwAvailable());
-}
-
-void IsolatedXRRuntimeProvider::SetOpenVrRuntimeStatus(RuntimeStatus status) {
-  SetRuntimeStatus(client_.get(), status,
-                   base::BindOnce(&CreateDevice<device::OpenVRDevice>),
-                   &openvr_device_);
-}
-#endif  // BUILDFLAG(ENABLE_OPENVR)
-
 #if BUILDFLAG(ENABLE_WINDOWS_MR)
 bool IsolatedXRRuntimeProvider::IsWMRHardwareAvailable() {
   return should_check_wmr_ && wmr_statics_->IsHardwareAvailable();
diff --git a/content/services/isolated_xr_device/xr_runtime_provider.h b/content/services/isolated_xr_device/xr_runtime_provider.h
index 1dd8ce2..85d1af2 100644
--- a/content/services/isolated_xr_device/xr_runtime_provider.h
+++ b/content/services/isolated_xr_device/xr_runtime_provider.h
@@ -13,8 +13,6 @@
 #include "mojo/public/cpp/bindings/remote.h"
 
 namespace device {
-class OculusDevice;
-class OpenVRDevice;
 class MixedRealityDevice;
 class MixedRealityDeviceStatics;
 class OpenXrDevice;
@@ -37,20 +35,6 @@
   void PollForDeviceChanges();
   void SetupPollingForDeviceChanges();
 
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-  bool IsOculusVrHardwareAvailable();
-  void SetOculusVrRuntimeStatus(RuntimeStatus status);
-  bool should_check_oculus_ = false;
-  std::unique_ptr<device::OculusDevice> oculus_device_;
-#endif
-
-#if BUILDFLAG(ENABLE_OPENVR)
-  bool IsOpenVrHardwareAvailable();
-  void SetOpenVrRuntimeStatus(RuntimeStatus status);
-  bool should_check_openvr_ = false;
-  std::unique_ptr<device::OpenVRDevice> openvr_device_;
-#endif
-
 #if BUILDFLAG(ENABLE_WINDOWS_MR)
   bool IsWMRHardwareAvailable();
   void SetWMRRuntimeStatus(RuntimeStatus status);
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
index da197e0..a80055b 100644
--- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-win.txt
@@ -1,5 +1,6 @@
 EVENT_OBJECT_FOCUS on <li#op1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=1
 EVENT_OBJECT_HIDE on <body> role=ROLE_SYSTEM_GROUPING INVISIBLE
+EVENT_OBJECT_SELECTION on <li#op1> role=ROLE_SYSTEM_LISTITEM name="Apple" SELECTED,FOCUSED,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=1
 IA2_EVENT_ACTIVE_DESCENDANT_CHANGED on <input> role=ROLE_SYSTEM_COMBOBOX EXPANDED,FOCUSABLE,HASPOPUP IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE,IA2_STATE_SUPPORTS_AUTOCOMPLETION
 IA2_EVENT_TEXT_INSERTED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE new_text={'<obj><obj>' start=0 end=2}
-IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE old_text={'<obj>' start=0 end=1}
\ No newline at end of file
+IA2_EVENT_TEXT_REMOVED on <#document> role=ROLE_SYSTEM_DOCUMENT value~=[doc-url] FOCUSABLE old_text={'<obj>' start=0 end=1}
diff --git a/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt
new file mode 100644
index 0000000..9ef6c48
--- /dev/null
+++ b/content/test/data/accessibility/event/children-changed-only-on-ancestor-expected-win.txt
@@ -0,0 +1,11 @@
+EVENT_OBJECT_HIDE on <div#article> role=ROLE_SYSTEM_DOCUMENT INVISIBLE
+EVENT_OBJECT_REORDER on <div#tree> role=ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild1" INVISIBLE,FOCUSABLE level=2
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild2" INVISIBLE,FOCUSABLE level=2
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild3" INVISIBLE,FOCUSABLE level=2
+=== Start Continuation ===
+EVENT_OBJECT_REORDER on <div#tree> role=ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild1" FOCUSABLE level=2 PosInSet=1 SetSize=3
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild2" FOCUSABLE level=2 PosInSet=2 SetSize=3
+EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_OUTLINEITEM name="grandchild3" FOCUSABLE level=2 PosInSet=3 SetSize=3
+EVENT_OBJECT_SHOW on <div#article> role=ROLE_SYSTEM_DOCUMENT
diff --git a/content/test/data/accessibility/event/children-changed-only-on-ancestor.html b/content/test/data/accessibility/event/children-changed-only-on-ancestor.html
new file mode 100644
index 0000000..3ddfbd4
--- /dev/null
+++ b/content/test/data/accessibility/event/children-changed-only-on-ancestor.html
@@ -0,0 +1,55 @@
+<!--
+@WIN-DENY:IA2_EVENT_TEXT_INSERTED*
+@WIN-DENY:IA2_EVENT_TEXT_REMOVED*
+@WIN-DENY:EVENT_OBJECT_STATECHANGE*
+@WIN-DENY:EVENT_OBJECT_LOCATIONCHANGE*
+-->
+<html>
+  <body>
+    <!-- Show/Hide events only need to occur on the root of what's shown/hidden,
+     not for each descendant. -->
+    <div role="tree" id="tree">
+      <div role="article" id="article">
+        <div role="group">
+          <div role="treeitem" tabindex="0">
+            <div role="link" id="child1">
+              <div id="grandchild1">grandchild1</div>
+            </div>
+          </div>
+          <div role="treeitem" tabindex="0">
+            <div role="link" id="child2">
+              <div id="grandchild2">grandchild2</div>
+            </div>
+          </div>
+          <div role="treeitem" tabindex="0">
+            <div role="link" id="child3">
+              <div id="grandchild3">grandchild3</div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <script>
+      const go_passes = [
+        // Hide action.
+        () => {
+          document.getElementById("article").setAttribute("aria-hidden", "true");
+          document.getElementById("article").setAttribute("style", "width: 0px; height: 0px;");
+        },
+
+        // Show action.
+        () => {
+          document.getElementById("article").setAttribute("aria-hidden", "false");
+          document.getElementById("article").setAttribute("style", "width: auto; height: auto;");
+        }
+      ];
+
+      let current_pass = 0;
+
+      function go() {
+        go_passes[current_pass++].call();
+        return current_pass < go_passes.length;
+      }
+    </script>
+  </body>
+</html>
diff --git a/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt b/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt
index 220897bf..eb1be9ce 100644
--- a/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt
+++ b/content/test/data/accessibility/event/expanded-changed-expected-uia-win.txt
@@ -1,6 +1,3 @@
 AriaProperties changed on role=link, name=Toggle
 AriaProperties changed on role=list, name=list
-AriaProperties changed on role=listitem, name=list item 1
-AriaProperties changed on role=listitem, name=list item 2
-AriaProperties changed on role=listitem, name=list item 3
 ExpandCollapseExpandCollapseState changed on role=link, name=Toggle
diff --git a/device/base/features.cc b/device/base/features.cc
index 6b004e1..ea69413f 100644
--- a/device/base/features.cc
+++ b/device/base/features.cc
@@ -39,16 +39,6 @@
 };
 #endif  // BUILDFLAG(ENABLE_VR)
 namespace features {
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-// Controls WebXR support for the Oculus Runtime.
-const base::Feature kOculusVR{"OculusVR", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // ENABLE_OCULUS_VR
-
-#if BUILDFLAG(ENABLE_OPENVR)
-// Controls WebXR support for the OpenVR Runtime.
-const base::Feature kOpenVR{"OpenVR", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // ENABLE_OPENVR
-
 #if BUILDFLAG(ENABLE_OPENXR)
 // Controls WebXR support for the OpenXR Runtime.
 const base::Feature kOpenXR{"OpenXR", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/device/base/features.h b/device/base/features.h
index e017e52..1d9143d 100644
--- a/device/base/features.h
+++ b/device/base/features.h
@@ -28,12 +28,6 @@
 // New features should be added to the device::features namespace.
 
 namespace features {
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-DEVICE_BASE_EXPORT extern const base::Feature kOculusVR;
-#endif  // ENABLE_OCULUS_VR
-#if BUILDFLAG(ENABLE_OPENVR)
-DEVICE_BASE_EXPORT extern const base::Feature kOpenVR;
-#endif  // ENABLE_OPENVR
 #if BUILDFLAG(ENABLE_OPENXR)
 DEVICE_BASE_EXPORT extern const base::Feature kOpenXR;
 #endif  // ENABLE_OPENXR
diff --git a/gpu/ipc/service/image_transport_surface_win.cc b/gpu/ipc/service/image_transport_surface_win.cc
index 3cc8901..82457dbe 100644
--- a/gpu/ipc/service/image_transport_surface_win.cc
+++ b/gpu/ipc/service/image_transport_surface_win.cc
@@ -21,6 +21,20 @@
 #include "ui/gl/vsync_provider_win.h"
 
 namespace gpu {
+namespace {
+gl::DirectCompositionSurfaceWin::Settings
+CreateDirectCompositionSurfaceSettings(
+    const GpuDriverBugWorkarounds& workarounds) {
+  gl::DirectCompositionSurfaceWin::Settings settings;
+  settings.disable_nv12_dynamic_textures =
+      workarounds.disable_nv12_dynamic_textures;
+  settings.disable_larger_than_screen_overlays =
+      workarounds.disable_larger_than_screen_overlays;
+  settings.disable_vp_scaling = workarounds.disable_vp_scaling;
+  settings.use_angle_texture_offset = features::IsUsingSkiaRenderer();
+  return settings;
+}
+}  // namespace
 
 // static
 scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface(
@@ -31,22 +45,12 @@
   scoped_refptr<gl::GLSurface> surface;
 
   if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) {
-    auto vsync_provider =
-        std::make_unique<gl::VSyncProviderWin>(surface_handle);
-
     if (gl::DirectCompositionSurfaceWin::IsDirectCompositionSupported()) {
-      const auto& workarounds = delegate->GetFeatureInfo()->workarounds();
-      gl::DirectCompositionSurfaceWin::Settings settings;
-      settings.disable_nv12_dynamic_textures =
-          workarounds.disable_nv12_dynamic_textures;
-      settings.disable_larger_than_screen_overlays =
-          workarounds.disable_larger_than_screen_overlays;
-      settings.disable_vp_scaling = workarounds.disable_vp_scaling;
-      settings.use_angle_texture_offset = features::IsUsingSkiaRenderer();
       auto vsync_callback = delegate->GetGpuVSyncCallback();
+      auto settings = CreateDirectCompositionSurfaceSettings(
+          delegate->GetFeatureInfo()->workarounds());
       auto dc_surface = base::MakeRefCounted<gl::DirectCompositionSurfaceWin>(
-          std::move(vsync_provider), std::move(vsync_callback), surface_handle,
-          settings);
+          surface_handle, std::move(vsync_callback), settings);
       if (!dc_surface->Initialize(gl::GLSurfaceFormat()))
         return nullptr;
       delegate->DidCreateAcceleratedSurfaceChildWindow(surface_handle,
@@ -55,7 +59,8 @@
     } else {
       surface = gl::InitializeGLSurface(
           base::MakeRefCounted<gl::NativeViewGLSurfaceEGL>(
-              surface_handle, std::move(vsync_provider)));
+              surface_handle,
+              std::make_unique<gl::VSyncProviderWin>(surface_handle)));
       if (!surface)
         return nullptr;
     }
diff --git a/infra/config/dev.star b/infra/config/dev.star
index 81993f7..e4e8674 100755
--- a/infra/config/dev.star
+++ b/infra/config/dev.star
@@ -6,7 +6,7 @@
 # See https://chromium.googlesource.com/infra/luci/luci-go/+/HEAD/lucicfg/doc/README.md
 # for information on starlark/lucicfg
 
-load("//project.star", "master_only_exec")
+load("//lib/branches.star", "branches")
 
 lucicfg.check_version(
     min = "1.18.4",
@@ -29,4 +29,4 @@
     fail_on_warnings = True,
 )
 
-master_only_exec("//dev/dev.star")
+branches.exec("//dev/dev.star")
diff --git a/infra/config/generated/luci-notify.cfg b/infra/config/generated/luci-notify.cfg
index 52f3364..bd988358 100644
--- a/infra/config/generated/luci-notify.cfg
+++ b/infra/config/generated/luci-notify.cfg
@@ -2917,6 +2917,25 @@
     on_occurrence: FAILURE
     failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
     email {
+      rotation_urls: "https://chrome-ops-rotation-proxy.appspot.com/current/oncallator:chrome-build-sheriff"
+    }
+    template: "tree_closure_email_template"
+  }
+  builders {
+    bucket: "ci"
+    name: "linux-lacros-builder-rel"
+    repository: "https://chromium.googlesource.com/chromium/src"
+  }
+  tree_closers {
+    tree_status_host: "chromium-status.appspot.com"
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+  }
+}
+notifiers {
+  notifications {
+    on_occurrence: FAILURE
+    failed_step_regexp: "bot_update|compile|gclient runhooks|runhooks|update"
+    email {
       recipients: "thomasanderson@chromium.org"
     }
   }
diff --git a/infra/config/main.star b/infra/config/main.star
index d4e0113..fbcde3fa1 100755
--- a/infra/config/main.star
+++ b/infra/config/main.star
@@ -6,7 +6,8 @@
 # See https://chromium.googlesource.com/infra/luci/luci-go/+/HEAD/lucicfg/doc/README.md
 # for information on starlark/lucicfg
 
-load("//project.star", "master_only_exec", "settings")
+load("//lib/branches.star", "branches")
+load("//project.star", "settings")
 
 lucicfg.check_version(
     min = "1.18.4",
@@ -121,12 +122,12 @@
 exec("//notifiers.star")
 
 exec("//subprojects/chromium/subproject.star")
-master_only_exec("//subprojects/codesearch/subproject.star")
-master_only_exec("//subprojects/findit/subproject.star")
-master_only_exec("//subprojects/goma/subproject.star")
-master_only_exec("//subprojects/webrtc/subproject.star")
+branches.exec("//subprojects/codesearch/subproject.star")
+branches.exec("//subprojects/findit/subproject.star")
+branches.exec("//subprojects/goma/subproject.star")
+branches.exec("//subprojects/webrtc/subproject.star")
 
-master_only_exec("//generators/cq-builders-md.star")
+branches.exec("//generators/cq-builders-md.star")
 
 # This should be exec'ed before exec'ing scheduler-noop-jobs.star because
 # attempting to read the buildbucket field that is not set for the noop jobs
@@ -135,7 +136,7 @@
 # problems when the number of builders with the same name goes from 1 to >1 or
 # vice-versa. This generator makes sure both the bucketed and non-bucketed IDs
 # work so that there aren't transient failures when the configuration changes
-master_only_exec("//generators/scheduler-bucketed-jobs.star")
+branches.exec("//generators/scheduler-bucketed-jobs.star")
 
 # TODO(https://crbug.com/819899) There are a number of noop jobs for dummy
 # builders defined due to legacy requirements that trybots mirror CI bots
diff --git a/infra/config/project.star b/infra/config/project.star
index 8ad796c..84dcf47 100644
--- a/infra/config/project.star
+++ b/infra/config/project.star
@@ -6,6 +6,8 @@
     project = "chromium",
     # Switch this to False for branches
     is_master = True,
+    # Switch this to True for LTC/LTS branches
+    is_lts_branch = False,
     ref = "refs/heads/master",
     ci_bucket = "ci",
     ci_poller = "master-gitiles-trigger",
@@ -39,10 +41,6 @@
 
 lucicfg.generator(_generate_project_pyl)
 
-def master_only_exec(f):
-    if settings.is_master:
-        exec(f)
-
 # The branch numbers of branches that we have builders running for (including
 # milestone-specific projects)
 # Branch numbers for milestones can be viewed in the chromium column at
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index 57a02d1..d89e233 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 load("//lib/branches.star", "branches")
-load("//lib/builders.star", "builder_name", "goma", "os", "xcode_cache")
+load("//lib/builders.star", "builder_name", "cpu", "goma", "os", "xcode_cache")
 load("//lib/ci.star", "ci")
 load("//project.star", "settings")
 
@@ -274,9 +274,155 @@
     },
 )
 
+# The chromium.clang console includes some entries for builders from the chrome project
+[branches.console_view_entry(
+    builder = "chrome:ci/{}".format(name),
+    console_view = "chromium.clang",
+    category = category,
+    short_name = short_name,
+) for name, category, short_name in (
+    ("ToTLinuxOfficial", "ToT Linux", "ofi"),
+    ("ToTMacOfficial", "ToT Mac", "ofi"),
+    ("ToTWin", "ToT Windows", "rel"),
+    ("ToTWin64", "ToT Windows|x64", "rel"),
+    ("ToTWinOfficial", "ToT Windows", "ofi"),
+    ("ToTWinThinLTO64", "ToT Windows|x64", "lto"),
+    ("clang-tot-device", "iOS|internal", "dev"),
+)]
+
+# The main console includes some entries for builders from the chrome project
+[branches.console_view_entry(
+    builder = "chrome:ci/{}".format(name),
+    console_view = "main",
+    category = "chrome",
+    short_name = short_name,
+) for name, short_name in (
+    ("linux-chromeos-chrome", "cro"),
+    ("linux-chrome", "lnx"),
+    ("mac-chrome", "mac"),
+    ("win-chrome", "win"),
+    ("win64-chrome", "win"),
+)]
+
 # Builders are sorted first lexicographically by the function used to define
 # them, then lexicographically by their name
 
+ci.builder(
+    name = "android-avd-packager",
+    executable = "recipe:android/avd_packager",
+    properties = {
+        "avd_configs": [
+            "tools/android/avd/proto/creation/generic_android23.textpb",
+            "tools/android/avd/proto/creation/generic_android28.textpb",
+            "tools/android/avd/proto/creation/generic_android29.textpb",
+            "tools/android/avd/proto/creation/generic_playstore_android28.textpb",
+        ],
+    },
+    schedule = "0 7 * * 0 *",
+    service_account = "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com",
+    triggered_by = [],
+)
+
+ci.builder(
+    name = "android-sdk-packager",
+    executable = "recipe:android/sdk_packager",
+    schedule = "0 7 * * 0 *",
+    service_account = "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com",
+    triggered_by = [],
+    properties = {
+        # We still package part of build-tools;25.0.2 to support
+        # http://bit.ly/2KNUygZ
+        "packages": [
+            {
+                "sdk_package_name": "build-tools;25.0.2",
+                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/25.0.2.yaml",
+            },
+            {
+                "sdk_package_name": "build-tools;29.0.2",
+                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/29.0.2.yaml",
+            },
+            {
+                "sdk_package_name": "build-tools;30.0.1",
+                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/30.0.1.yaml",
+            },
+            {
+                "sdk_package_name": "cmdline-tools;latest",
+                "cipd_yaml": "third_party/android_sdk/cipd/cmdline-tools.yaml",
+            },
+            {
+                "sdk_package_name": "emulator",
+                "cipd_yaml": "third_party/android_sdk/cipd/emulator.yaml",
+            },
+            {
+                "sdk_package_name": "extras;google;gcm",
+                "cipd_yaml": "third_party/android_sdk/cipd/extras/google/gcm.yaml",
+            },
+            {
+                "sdk_package_name": "patcher;v4",
+                "cipd_yaml": "third_party/android_sdk/cipd/patcher/v4.yaml",
+            },
+            {
+                "sdk_package_name": "platforms;android-29",
+                "cipd_yaml": "third_party/android_sdk/cipd/platforms/android-29.yaml",
+            },
+            {
+                "sdk_package_name": "platforms;android-30",
+                "cipd_yaml": "third_party/android_sdk/cipd/platforms/android-30.yaml",
+            },
+            {
+                "sdk_package_name": "platform-tools",
+                "cipd_yaml": "third_party/android_sdk/cipd/platform-tools.yaml",
+            },
+            {
+                "sdk_package_name": "sources;android-29",
+                "cipd_yaml": "third_party/android_sdk/cipd/sources/android-29.yaml",
+            },
+            # Not yet available as R is not released to AOSP.
+            #{
+            #    'sdk_package_name': 'sources;android-30',
+            #    'cipd_yaml': 'third_party/android_sdk/cipd/sources/android-30.yaml'
+            #},
+            {
+                "sdk_package_name": "system-images;android-29;google_apis;x86",
+                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-29/google_apis/x86.yaml",
+            },
+            {
+                "sdk_package_name": "system-images;android-29;google_apis_playstore;x86",
+                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-29/google_apis_playstore/x86.yaml",
+            },
+            {
+                "sdk_package_name": "system-images;android-30;google_apis;x86",
+                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-30/google_apis/x86.yaml",
+            },
+            {
+                "sdk_package_name": "system-images;android-30;google_apis_playstore;x86",
+                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-30/google_apis_playstore/x86.yaml",
+            },
+        ],
+    },
+)
+
+ci.android_builder(
+    name = "Android ASAN (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "builder|arm",
+        short_name = "san",
+    ),
+    # Higher build timeout since dbg ASAN builds can take a while on a clobber
+    # build.
+    execution_timeout = 4 * time.hour,
+    tree_closing = True,
+)
+
+ci.android_builder(
+    name = "Android WebView L (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "tester|webview",
+        short_name = "L",
+    ),
+    triggered_by = ["ci/Android arm Builder (dbg)"],
+)
+
 ci.android_builder(
     name = "Android WebView M (dbg)",
     branch_selector = branches.STANDARD_RELEASES,
@@ -389,6 +535,54 @@
 )
 
 ci.android_builder(
+    name = "Deterministic Android",
+    console_view_entry = ci.console_view_entry(
+        category = "builder|det",
+        short_name = "rel",
+    ),
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    notifies = ["Deterministic Android"],
+    tree_closing = True,
+)
+
+ci.android_builder(
+    name = "Deterministic Android (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "builder|det",
+        short_name = "dbg",
+    ),
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    notifies = ["Deterministic Android"],
+    tree_closing = True,
+)
+
+ci.android_builder(
+    name = "Lollipop Phone Tester",
+    console_view_entry = ci.console_view_entry(
+        category = "tester|phone",
+        short_name = "L",
+    ),
+    # We have limited phone capacity and thus limited ability to run
+    # tests in parallel, hence the high timeout.
+    execution_timeout = 6 * time.hour,
+    triggered_by = ["ci/Android arm Builder (dbg)"],
+)
+
+ci.android_builder(
+    name = "Lollipop Tablet Tester",
+    console_view_entry = ci.console_view_entry(
+        category = "tester|tablet",
+        short_name = "L",
+    ),
+    # We have limited tablet capacity and thus limited ability to run
+    # tests in parallel, hence the high timeout.
+    execution_timeout = 20 * time.hour,
+    triggered_by = ["ci/Android arm Builder (dbg)"],
+)
+
+ci.android_builder(
     name = "Marshmallow 64 bit Tester",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -401,6 +595,18 @@
 )
 
 ci.android_builder(
+    name = "Marshmallow Tablet Tester",
+    console_view_entry = ci.console_view_entry(
+        category = "tester|tablet",
+        short_name = "M",
+    ),
+    # We have limited tablet capacity and thus limited ability to run
+    # tests in parallel, hence the high timeout.
+    execution_timeout = 12 * time.hour,
+    triggered_by = ["ci/Android arm Builder (dbg)"],
+)
+
+ci.android_builder(
     name = "Nougat Phone Tester",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -425,6 +631,41 @@
 )
 
 ci.android_builder(
+    name = "android-10-arm64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "builder_tester|arm64",
+        short_name = "10",
+    ),
+)
+
+ci.android_builder(
+    name = "android-arm64-proguard-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "builder_tester|arm64",
+        short_name = "M proguard",
+    ),
+    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
+    execution_timeout = 6 * time.hour,
+)
+
+ci.android_builder(
+    name = "android-bfcache-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "bfcache",
+        short_name = "bfc",
+    ),
+)
+
+ci.android_builder(
+    name = "android-binary-size-generator",
+    executable = "recipe:binary_size_generator_tot",
+    console_view_entry = ci.console_view_entry(
+        category = "builder|other",
+        short_name = "size",
+    ),
+)
+
+ci.android_builder(
     name = "android-cronet-arm-dbg",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -449,6 +690,32 @@
 )
 
 ci.android_builder(
+    name = "android-cronet-arm64-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|arm64",
+        short_name = "dbg",
+    ),
+    notifies = ["cronet"],
+)
+
+ci.android_builder(
+    name = "android-cronet-arm64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|arm64",
+        short_name = "rel",
+    ),
+    notifies = ["cronet"],
+)
+
+ci.android_builder(
+    name = "android-cronet-asan-arm-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|asan",
+    ),
+    notifies = ["cronet"],
+)
+
+ci.android_builder(
     name = "android-cronet-kitkat-arm-rel",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -474,6 +741,55 @@
     triggered_by = [builder_name("android-cronet-arm-rel")],
 )
 
+# Runs on a specific machine with an attached phone
+ci.android_builder(
+    name = "android-cronet-marshmallow-arm64-perf-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|test|perf",
+        short_name = "m",
+    ),
+    cores = None,
+    cpu = None,
+    executable = "recipe:cronet",
+    notifies = ["cronet"],
+    os = os.ANDROID,
+)
+
+ci.android_builder(
+    name = "android-cronet-marshmallow-arm64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|test",
+        short_name = "m",
+    ),
+    notifies = ["cronet"],
+    triggered_by = ["android-cronet-arm64-rel"],
+)
+
+ci.android_builder(
+    name = "android-cronet-x86-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|x86",
+        short_name = "dbg",
+    ),
+    notifies = ["cronet"],
+)
+
+ci.android_builder(
+    name = "android-cronet-x86-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "cronet|x86",
+        short_name = "rel",
+    ),
+    notifies = ["cronet"],
+)
+
+ci.android_builder(
+    name = "android-incremental-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "tester|incremental",
+    ),
+)
+
 ci.android_builder(
     name = "android-lollipop-arm-rel",
     branch_selector = branches.STANDARD_RELEASES,
@@ -544,6 +860,79 @@
     tree_closing = True,
 )
 
+ci.android_builder(
+    name = "android-pie-x86-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "builder_tester|x86",
+        short_name = "P",
+    ),
+)
+
+ci.android_fyi_builder(
+    name = "Android WebLayer P FYI (rel)",
+    console_view_entry = ci.console_view_entry(
+        category = "weblayer",
+        short_name = "p-rel",
+    ),
+)
+
+ci.android_fyi_builder(
+    name = "android-weblayer-pie-x86-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "weblayer",
+        short_name = "p-x86-rel",
+    ),
+)
+
+ci.android_fyi_builder(
+    name = "Android WebView P FYI (rel)",
+    console_view_entry = ci.console_view_entry(
+        category = "webview",
+        short_name = "p-rel",
+    ),
+)
+
+ci.android_fyi_builder(
+    name = "android-marshmallow-x86-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "emulator|M|x86",
+        short_name = "rel",
+    ),
+    goma_jobs = goma.jobs.J150,
+)
+
+# TODO(hypan): remove this once there is no associated disabled tests
+ci.android_fyi_builder(
+    name = "android-pie-x86-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "emulator|P|x86",
+        short_name = "rel",
+    ),
+    goma_jobs = goma.jobs.J150,
+    schedule = "triggered",  # triggered manually via Scheduler UI
+)
+
+ci.chromium_builder(
+    name = "android-archive-dbg",
+    # Bump to 32 if needed.
+    console_view_entry = ci.console_view_entry(
+        category = "android",
+        short_name = "dbg",
+    ),
+    cores = 8,
+    main_console_view = "main",
+)
+
+ci.chromium_builder(
+    name = "android-archive-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "android",
+        short_name = "rel",
+    ),
+    cores = 32,
+    main_console_view = "main",
+)
+
 ci.chromium_builder(
     name = "android-official",
     branch_selector = branches.STANDARD_RELEASES,
@@ -572,6 +961,28 @@
 )
 
 ci.chromium_builder(
+    name = "linux-archive-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+        short_name = "dbg",
+    ),
+    # Bump to 32 if needed.
+    cores = 8,
+    main_console_view = "main",
+)
+
+ci.chromium_builder(
+    name = "linux-archive-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+        short_name = "rel",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    notifies = ["linux-archive-rel"],
+)
+
+ci.chromium_builder(
     name = "linux-official",
     branch_selector = branches.STANDARD_RELEASES,
     builderless = False,
@@ -591,6 +1002,51 @@
 )
 
 ci.chromium_builder(
+    name = "mac-archive-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "dbg",
+    ),
+    # Bump to 8 cores if needed.
+    cores = 4,
+    main_console_view = "main",
+    os = os.MAC_DEFAULT,
+)
+
+ci.chromium_builder(
+    name = "mac-archive-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "rel",
+    ),
+    main_console_view = "main",
+    os = os.MAC_DEFAULT,
+)
+
+ci.chromium_builder(
+    name = "win-archive-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "win|dbg",
+        short_name = "64",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    os = os.WINDOWS_DEFAULT,
+    tree_closing = False,
+)
+
+ci.chromium_builder(
+    name = "win-archive-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "win|rel",
+        short_name = "64",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    os = os.WINDOWS_DEFAULT,
+)
+
+ci.chromium_builder(
     name = "win-official",
     branch_selector = branches.STANDARD_RELEASES,
     main_console_view = settings.main_console_name,
@@ -605,6 +1061,29 @@
 )
 
 ci.chromium_builder(
+    name = "win32-archive-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "win|dbg",
+        short_name = "32",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    os = os.WINDOWS_DEFAULT,
+    tree_closing = False,
+)
+
+ci.chromium_builder(
+    name = "win32-archive-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "win|rel",
+        short_name = "32",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    os = os.WINDOWS_DEFAULT,
+)
+
+ci.chromium_builder(
     name = "win32-official",
     branch_selector = branches.STANDARD_RELEASES,
     main_console_view = settings.main_console_name,
@@ -619,6 +1098,33 @@
 )
 
 ci.chromiumos_builder(
+    name = "Linux ChromiumOS Full",
+    console_view_entry = ci.console_view_entry(
+        category = "default",
+        short_name = "ful",
+    ),
+    main_console_view = "main",
+)
+
+ci.chromiumos_builder(
+    name = "chromeos-amd64-generic-asan-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "simple|release|x64",
+        short_name = "asn",
+    ),
+    main_console_view = "main",
+)
+
+ci.chromiumos_builder(
+    name = "chromeos-amd64-generic-cfi-thin-lto-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "simple|release|x64",
+        short_name = "cfi",
+    ),
+    main_console_view = "main",
+)
+
+ci.chromiumos_builder(
     name = "chromeos-amd64-generic-dbg",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -641,6 +1147,15 @@
 )
 
 ci.chromiumos_builder(
+    name = "chromeos-arm-generic-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "simple|debug",
+        short_name = "arm",
+    ),
+    main_console_view = "main",
+)
+
+ci.chromiumos_builder(
     name = "chromeos-arm-generic-rel",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -652,6 +1167,15 @@
 )
 
 ci.chromiumos_builder(
+    name = "chromeos-kevin-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "simple|release",
+        short_name = "kvn",
+    ),
+    main_console_view = "main",
+)
+
+ci.chromiumos_builder(
     name = "linux-chromeos-dbg",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -683,8 +1207,6 @@
     ),
     cq_mirrors_console_view = settings.cq_mirrors_console_name,
     main_console_view = settings.main_console_name,
-    # TODO(crbug.com/1104291): Enable tree closing.
-    tree_closing = False,
 )
 
 ci.chromiumos_builder(
@@ -701,6 +1223,312 @@
     tree_closing = False,
 )
 
+ci.clang_builder(
+    name = "CFI Linux CF",
+    goma_backend = goma.backend.RBE_PROD,
+    console_view_entry = ci.console_view_entry(
+        category = "CFI|Linux",
+        short_name = "CF",
+    ),
+    notifies = ["CFI Linux"],
+)
+
+ci.clang_builder(
+    name = "CFI Linux ToT",
+    console_view_entry = ci.console_view_entry(
+        category = "CFI|Linux",
+        short_name = "ToT",
+    ),
+    notifies = ["CFI Linux"],
+)
+
+ci.clang_builder(
+    name = "CrWinAsan",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows|Asan",
+        short_name = "asn",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "CrWinAsan(dll)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows|Asan",
+        short_name = "dll",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTAndroid",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "rel",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroid (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "dbg",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroid x64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "x64",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroid64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "a64",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroidASan",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "asn",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroidCFI",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "cfi",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTAndroidOfficial",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Android",
+        short_name = "off",
+    ),
+)
+
+def clang_tot_linux_builder(short_name, category = "ToT Linux", **kwargs):
+    ci.clang_builder(
+        console_view_entry = ci.console_view_entry(
+            category = category,
+            short_name = short_name,
+        ),
+        notifies = [luci.notifier(
+            name = "ToT Linux notifier",
+            on_new_status = ["FAILURE"],
+            notify_emails = ["thomasanderson@chromium.org"],
+        )],
+        **kwargs
+    )
+
+clang_tot_linux_builder(
+    name = "ToTLinux",
+    short_name = "rel",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinux (dbg)",
+    short_name = "dbg",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxASan",
+    short_name = "asn",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxASanLibfuzzer",
+    # Requires a large disk, so has a machine specifically devoted to it
+    builderless = False,
+    short_name = "fuz",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxCoverage",
+    category = "ToT Code Coverage",
+    short_name = "linux",
+    executable = "recipe:chromium_clang_coverage_tot",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxMSan",
+    short_name = "msn",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxTSan",
+    short_name = "tsn",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxThinLTO",
+    short_name = "lto",
+)
+
+clang_tot_linux_builder(
+    name = "ToTLinuxUBSanVptr",
+    short_name = "usn",
+)
+
+ci.clang_builder(
+    name = "ToTWin(dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows",
+        short_name = "dbg",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWin(dll)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows",
+        short_name = "dll",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWin64(dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows|x64",
+        short_name = "dbg",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWin64(dll)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows|x64",
+        short_name = "dll",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWinASanLibfuzzer",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows|Asan",
+        short_name = "fuz",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWinCFI",
+    console_view_entry = ci.console_view_entry(
+        category = "CFI|Win",
+        short_name = "x86",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "ToTWinCFI64",
+    console_view_entry = ci.console_view_entry(
+        category = "CFI|Win",
+        short_name = "x64",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.clang_builder(
+    name = "UBSanVptr Linux",
+    console_view_entry = ci.console_view_entry(
+        short_name = "usn",
+    ),
+    goma_backend = goma.backend.RBE_PROD,
+)
+
+ci.clang_builder(
+    name = "linux-win_cross-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Windows",
+        short_name = "lxw",
+    ),
+)
+
+ci.clang_builder(
+    name = "ToTiOS",
+    caches = [xcode_cache.x11e146],
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|public",
+        short_name = "sim",
+    ),
+    cores = None,
+    os = os.MAC_10_14,
+    properties = {
+        "xcode_build_version": "11e146",
+    },
+    ssd = True,
+)
+
+ci.clang_builder(
+    name = "ToTiOSDevice",
+    caches = [xcode_cache.x11e146],
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|public",
+        short_name = "dev",
+    ),
+    cores = None,
+    os = os.MAC_10_14,
+    properties = {
+        "xcode_build_version": "11e146",
+    },
+    ssd = True,
+)
+
+ci.clang_mac_builder(
+    name = "ToTMac",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Mac",
+        short_name = "rel",
+    ),
+)
+
+ci.clang_mac_builder(
+    name = "ToTMac (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Mac",
+        short_name = "dbg",
+    ),
+)
+
+ci.clang_mac_builder(
+    name = "ToTMacASan",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Mac",
+        short_name = "asn",
+    ),
+)
+
+ci.clang_mac_builder(
+    name = "ToTMacCoverage",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT Code Coverage",
+        short_name = "mac",
+    ),
+    executable = "recipe:chromium_clang_coverage_tot",
+)
+
+ci.dawn_builder(
+    name = "Dawn Linux x64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Linux|Builder",
+        short_name = "x64",
+    ),
+)
+
 ci.dawn_builder(
     name = "Dawn Linux x64 DEPS Builder",
     branch_selector = branches.STANDARD_RELEASES,
@@ -741,6 +1569,39 @@
 )
 
 ci.dawn_builder(
+    name = "Dawn Linux x64 Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Linux|Intel",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Linux x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Linux x64 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Linux|Nvidia",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Linux x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Mac x64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Mac|Builder",
+        short_name = "x64",
+    ),
+    builderless = False,
+    cores = None,
+    os = os.MAC_ANY,
+)
+
+ci.dawn_builder(
     name = "Dawn Mac x64 DEPS Builder",
     branch_selector = branches.STANDARD_RELEASES,
     builderless = False,
@@ -785,6 +1646,46 @@
 )
 
 ci.dawn_builder(
+    name = "Dawn Mac x64 Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Mac|AMD",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Mac x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Mac x64 Release (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Mac|Intel",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Mac x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Win10 x64 ASAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|ASAN",
+        short_name = "x64",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.dawn_builder(
+    name = "Dawn Win10 x64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Builder",
+        short_name = "x64",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
+ci.dawn_builder(
     name = "Dawn Win10 x64 DEPS Builder",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -824,6 +1725,39 @@
     triggered_by = [builder_name("Dawn Win10 x64 DEPS Builder")],
 )
 
+# Note that the Win testers are all thin Linux VMs, triggering jobs on the
+# physical Win hardware in the Swarming pool, which is why they run on linux
+ci.dawn_builder(
+    name = "Dawn Win10 x64 Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Intel",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Win10 x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Win10 x64 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Nvidia",
+        short_name = "x64",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Win10 x64 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Win10 x86 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Builder",
+        short_name = "x86",
+    ),
+    os = os.WINDOWS_ANY,
+)
+
 ci.dawn_builder(
     name = "Dawn Win10 x86 DEPS Builder",
     branch_selector = branches.STANDARD_RELEASES,
@@ -864,6 +1798,448 @@
     triggered_by = [builder_name("Dawn Win10 x86 DEPS Builder")],
 )
 
+# Note that the Win testers are all thin Linux VMs, triggering jobs on the
+# physical Win hardware in the Swarming pool, which is why they run on linux
+ci.dawn_builder(
+    name = "Dawn Win10 x86 Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Intel",
+        short_name = "x86",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Win10 x86 Builder"],
+)
+
+ci.dawn_builder(
+    name = "Dawn Win10 x86 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT|Windows|Nvidia",
+        short_name = "x86",
+    ),
+    cores = 2,
+    os = os.LINUX_DEFAULT,
+    triggered_by = ["Dawn Win10 x86 Builder"],
+)
+
+ci.fuzz_builder(
+    name = "ASAN Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan",
+        short_name = "dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ASan Debug (32-bit x86 with V8-ARM)",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan|x64 v8-ARM",
+        short_name = "dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ASAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan",
+        short_name = "rel",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 5,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ASan Release (32-bit x86 with V8-ARM)",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan|x64 v8-ARM",
+        short_name = "rel",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ASAN Release Media",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan",
+        short_name = "med",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "Afl Upload Linux ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "afl",
+        short_name = "afl",
+    ),
+    executable = "recipe:chromium_afl",
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ASan Release Media (32-bit x86 with V8-ARM)",
+    console_view_entry = ci.console_view_entry(
+        category = "linux asan|x64 v8-ARM",
+        short_name = "med",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "ChromiumOS ASAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "cros asan",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 6,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "MSAN Release (chained origins)",
+    console_view_entry = ci.console_view_entry(
+        category = "linux msan",
+        short_name = "org",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "MSAN Release (no origins)",
+    console_view_entry = ci.console_view_entry(
+        category = "linux msan",
+        short_name = "rel",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "Mac ASAN Release",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "mac asan",
+        short_name = "rel",
+    ),
+    cores = 4,
+    os = os.MAC_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 2,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "Mac ASAN Release Media",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "mac asan",
+        short_name = "med",
+    ),
+    cores = 4,
+    os = os.MAC_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 2,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "TSAN Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "linux tsan",
+        short_name = "dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "TSAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "linux tsan",
+        short_name = "rel",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 3,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "UBSan Release",
+    console_view_entry = ci.console_view_entry(
+        category = "linux UBSan",
+        short_name = "rel",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "UBSan vptr Release",
+    console_view_entry = ci.console_view_entry(
+        category = "linux UBSan",
+        short_name = "vpt",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 4,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "Win ASan Release",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "win asan",
+        short_name = "rel",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 7,
+    ),
+)
+
+ci.fuzz_builder(
+    name = "Win ASan Release Media",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "win asan",
+        short_name = "med",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 6,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Chrome OS ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "chromeos-asan",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 3,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 5,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux ASan Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux-dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 5,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux MSan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux-msan",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 5,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux UBSan",
+    # Do not use builderless for this (crbug.com/980080).
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux-ubsan",
+    ),
+    execution_timeout = 3 * time.hour + 30 * time.minute,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 5,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux V8-ARM64 ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "arm64",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 1,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux V8-ARM64 ASan Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "arm64-dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 1,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux32 ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux32",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 3,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux32 ASan Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "linux32-dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 3,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux32 V8-ARM ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "arm",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 1,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Linux32 V8-ARM ASan Debug",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "arm-dbg",
+    ),
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 1,
+    ),
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Mac ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "mac-asan",
+    ),
+    cores = 24,
+    execution_timeout = 4 * time.hour,
+    os = os.MAC_DEFAULT,
+)
+
+ci.fuzz_libfuzzer_builder(
+    name = "Libfuzzer Upload Windows ASan",
+    console_view_entry = ci.console_view_entry(
+        category = "libfuzz",
+        short_name = "win-asan",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 3,
+    ),
+)
+
+ci.fyi_builder(
+    name = "Closure Compilation Linux",
+    console_view_entry = ci.console_view_entry(
+        category = "closure_compilation",
+    ),
+    executable = "recipe:closure_compilation",
+    notifies = ["Closure Compilation Linux"],
+)
+
+ci.fyi_builder(
+    name = "Linux Viz",
+    console_view_entry = ci.console_view_entry(
+        category = "viz",
+    ),
+)
+
+ci.fyi_builder(
+    name = "Linux remote_run Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "remote_run",
+    ),
+)
+
+ci.fyi_builder(
+    name = "Linux remote_run Tester",
+    console_view_entry = ci.console_view_entry(
+        category = "remote_run",
+    ),
+    triggered_by = ["Linux remote_run Builder"],
+)
+
+ci.fyi_builder(
+    name = "Mojo Android",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "and",
+    ),
+)
+
+ci.fyi_builder(
+    name = "Mojo ChromiumOS",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "cr",
+    ),
+)
+
+ci.fyi_builder(
+    name = "Mojo Linux",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "lnx",
+    ),
+)
+
+ci.fyi_builder(
+    name = "Site Isolation Android",
+    console_view_entry = ci.console_view_entry(
+        category = "site_isolation",
+    ),
+    notifies = ["Site Isolation Android"],
+)
+
 ci.fyi_builder(
     name = "VR Linux",
     branch_selector = branches.STANDARD_RELEASES,
@@ -874,6 +2250,492 @@
     main_console_view = main_console_if_on_branch(),
 )
 
+ci.fyi_builder(
+    name = "android-mojo-webview-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "aw",
+    ),
+)
+
+ci.fyi_builder(
+    name = "chromeos-amd64-generic-lacros-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "chromeos",
+    ),
+    properties = {
+        # The format of these properties is defined at archive/properties.proto
+        "$build/archive": {
+            "archive_datas": [
+                # The list of files and dirs should be synched with
+                # _TRACKED_ITEMS in //build/lacros/lacros_resource_sizes.py.
+                {
+                    "files": [
+                        "chrome",
+                        "chrome_100_percent.pak",
+                        "chrome_200_percent.pak",
+                        "crashpad_handler",
+                        "headless_lib.pak",
+                        "icudtl.dat",
+                        "nacl_helper",
+                        "nacl_irt_x86_64.nexe",
+                        "resources.pak",
+                        "snapshot_blob.bin",
+                    ],
+                    "dirs": ["locales", "swiftshader"],
+                    "gcs_bucket": "chromium-lacros-fishfood",
+                    "gcs_path": "x86_64/{%position%}/lacros.zip",
+                    "archive_type": "ARCHIVE_TYPE_ZIP",
+                },
+            ],
+        },
+    },
+)
+
+ci.fyi_builder(
+    name = "fuchsia-fyi-arm64-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|a64",
+        short_name = "dbg",
+    ),
+    notifies = ["cr-fuchsia"],
+)
+
+ci.fyi_builder(
+    name = "fuchsia-fyi-arm64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|a64",
+        short_name = "rel",
+    ),
+    notifies = ["cr-fuchsia"],
+)
+
+ci.fyi_builder(
+    name = "fuchsia-fyi-x64-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|x64",
+        short_name = "dbg",
+    ),
+    notifies = ["cr-fuchsia"],
+)
+
+ci.fyi_builder(
+    name = "fuchsia-fyi-x64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|x64",
+        short_name = "rel",
+    ),
+    notifies = ["cr-fuchsia"],
+)
+
+ci.fyi_builder(
+    name = "linux-annotator-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "network|traffic|annotations",
+        short_name = "lnx",
+    ),
+    notifies = ["annotator-rel"],
+)
+
+ci.fyi_builder(
+    name = "linux-ash-chromium-builder-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "default",
+        short_name = "lcr",
+    ),
+    properties = {
+        # The format of these properties is defined at archive/properties.proto
+        "$build/archive": {
+            "archive_datas": [
+                {
+                    "files": [
+                        "chrome",
+                        "chrome_100_percent.pak",
+                        "chrome_200_percent.pak",
+                        "crashpad_handler",
+                        "headless_lib.pak",
+                        "icudtl.dat",
+                        "libminigbm.so",
+                        "nacl_helper",
+                        "nacl_irt_x86_64.nexe",
+                        "resources.pak",
+                        "snapshot_blob.bin",
+                    ],
+                    "dirs": ["locales", "swiftshader"],
+                    "gcs_bucket": "ash-chromium-on-linux-prebuilts",
+                    "gcs_path": "x86_64/{%position%}/ash-chromium.zip",
+                    "archive_type": "ARCHIVE_TYPE_ZIP",
+                    "latest_upload": {
+                        "gcs_path": "x86_64/latest/ash-chromium.txt",
+                        "gcs_file_content": "{%position%}",
+                    },
+                },
+            ],
+        },
+    },
+)
+
+ci.fyi_builder(
+    name = "linux-blink-animation-use-time-delta",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|blink",
+        short_name = "TD",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-blink-heap-concurrent-marking-tsan-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|blink",
+        short_name = "CM",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-blink-heap-verification",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|blink",
+        short_name = "VF",
+    ),
+    notifies = ["linux-blink-heap-verification"],
+)
+
+ci.fyi_builder(
+    name = "linux-chromium-tests-staging-builder",
+    console_view_entry = ci.console_view_entry(
+        category = "recipe|staging|linux",
+        short_name = "bld",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-chromium-tests-staging-tests",
+    console_view_entry = ci.console_view_entry(
+        category = "recipe|staging|linux",
+        short_name = "tst",
+    ),
+    triggered_by = ["linux-chromium-tests-staging-builder"],
+)
+
+ci.fyi_builder(
+    name = "linux-fieldtrial-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-lacros-builder-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-lacros-tester-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+    ),
+    triggered_by = ["linux-lacros-builder-fyi-rel"],
+)
+
+ci.fyi_builder(
+    name = "linux-perfetto-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+    ),
+)
+
+ci.fyi_builder(
+    name = "linux-wpt-fyi-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+    ),
+    experimental = True,
+    goma_backend = None,
+)
+
+# This is launching & collecting entirely isolated tests.
+# OS shouldn't matter.
+ci.fyi_builder(
+    name = "mac-osxbeta-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "beta",
+    ),
+    goma_backend = None,
+    main_console_view = None,
+    triggered_by = ["ci/Mac Builder"],
+)
+
+ci.fyi_builder(
+    name = "mac-omaha-builder-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "bld",
+    ),
+    os = os.MAC_ANY,
+    cpu = cpu.X86_64,
+    builderless = True,
+    cores = None,
+)
+
+ci.fyi_builder(
+    name = "mac10.10-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.10",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "mac10.11-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.11",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "mac10.12-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.12",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "mac10.13-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.13",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "mac10.14-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.14",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "mac10.15-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|mac",
+        short_name = "10.15",
+    ),
+    triggered_by = ["mac-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "win-omaha-builder-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|win",
+        short_name = "bld",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    cpu = cpu.X86,
+)
+
+ci.fyi_builder(
+    name = "win7-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|win",
+        short_name = "7",
+    ),
+    triggered_by = ["win-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "win10-omaha-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "updater|win",
+        short_name = "10",
+    ),
+    os = os.WINDOWS_10,
+    triggered_by = ["win-omaha-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "win-pixel-builder-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "win10",
+    ),
+    os = os.WINDOWS_10,
+)
+
+ci.fyi_builder(
+    name = "win-pixel-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "win10",
+    ),
+    os = None,
+    triggered_by = ["win-pixel-builder-rel"],
+)
+
+ci.fyi_builder(
+    name = "linux-upload-perfetto",
+    console_view_entry = ci.console_view_entry(
+        category = "perfetto",
+        short_name = "lnx",
+    ),
+    os = os.LINUX_DEFAULT,
+)
+
+ci.fyi_builder(
+    name = "mac-upload-perfetto",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "perfetto",
+        short_name = "mac",
+    ),
+    os = os.MAC_DEFAULT,
+    schedule = "with 3h interval",
+    triggered_by = [],
+)
+
+ci.fyi_builder(
+    name = "win-upload-perfetto",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "perfetto",
+        short_name = "win",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    schedule = "with 3h interval",
+    triggered_by = [],
+)
+
+ci.fyi_celab_builder(
+    name = "win-celab-builder-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "celab",
+    ),
+    schedule = "0 0,6,12,18 * * *",
+    triggered_by = [],
+)
+
+ci.fyi_celab_builder(
+    name = "win-celab-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "celab",
+    ),
+    triggered_by = ["win-celab-builder-rel"],
+)
+
+ci.fyi_coverage_builder(
+    name = "android-code-coverage",
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "and",
+    ),
+    use_java_coverage = True,
+    schedule = "triggered",
+    triggered_by = [],
+)
+
+ci.fyi_coverage_builder(
+    name = "android-code-coverage-native",
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "ann",
+    ),
+    use_clang_coverage = True,
+)
+
+ci.fyi_coverage_builder(
+    name = "ios-simulator-code-coverage",
+    caches = [xcode_cache.x12a8189n],
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "ios",
+    ),
+    cores = None,
+    os = os.MAC_10_15,
+    use_clang_coverage = True,
+    coverage_exclude_sources = "ios_test_files_and_test_utils",
+    coverage_test_types = ["overall", "unit"],
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_coverage_builder(
+    name = "linux-chromeos-code-coverage",
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "lcr",
+    ),
+    use_clang_coverage = True,
+    schedule = "triggered",
+    triggered_by = [],
+)
+
+ci.fyi_coverage_builder(
+    name = "linux-code-coverage",
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "lnx",
+    ),
+    use_clang_coverage = True,
+    triggered_by = [],
+)
+
+ci.fyi_coverage_builder(
+    name = "mac-code-coverage",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "mac",
+    ),
+    cores = 24,
+    os = os.MAC_ANY,
+    use_clang_coverage = True,
+)
+
+ci.fyi_coverage_builder(
+    name = "win10-code-coverage",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "code_coverage",
+        short_name = "win",
+    ),
+    os = os.WINDOWS_DEFAULT,
+    use_clang_coverage = True,
+)
+
+ci.fyi_ios_builder(
+    name = "ios-asan",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS",
+        short_name = "asan",
+    ),
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_ios_builder(
+    name = "ios-simulator-cr-recipe",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS",
+        short_name = "chr",
+    ),
+    executable = "recipe:chromium",
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
 ci.fyi_ios_builder(
     name = "ios-simulator-cronet",
     branch_selector = branches.STANDARD_RELEASES,
@@ -890,6 +2752,225 @@
     },
 )
 
+ci.fyi_ios_builder(
+    name = "ios-simulator-multi-window",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS",
+        short_name = "mwd",
+    ),
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_ios_builder(
+    name = "ios-webkit-tot",
+    caches = [xcode_cache.x11e608cwk],
+    console_view_entry = ci.console_view_entry(
+        category = "iOS",
+        short_name = "wk",
+    ),
+    executable = "recipe:chromium",
+    properties = {
+        "xcode_build_version": "11e608cwk",
+    },
+    schedule = "0 1-23/6 * * *",
+    triggered_by = [],
+)
+
+ci.fyi_ios_builder(
+    name = "ios13-beta-simulator",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|iOS13",
+        short_name = "ios13",
+    ),
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+    schedule = "0 0,12 * * *",
+    triggered_by = [],
+)
+
+ci.fyi_ios_builder(
+    name = "ios13-sdk-device",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|iOS13",
+        short_name = "dev",
+    ),
+    caches = [xcode_cache.x12a8189n],
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_ios_builder(
+    name = "ios13-sdk-simulator",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|iOS13",
+        short_name = "sdk13",
+    ),
+    caches = [xcode_cache.x12a8189n],
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+    schedule = "0 6,18 * * *",
+    triggered_by = [],
+)
+
+ci.fyi_ios_builder(
+    name = "ios14-beta-simulator",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|iOS14",
+        short_name = "ios14",
+    ),
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_ios_builder(
+    name = "ios14-sdk-simulator",
+    console_view_entry = ci.console_view_entry(
+        category = "iOS|iOS14",
+        short_name = "sdk14",
+    ),
+    caches = [xcode_cache.x12a8189n],
+    executable = "recipe:chromium",
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.fyi_mac_builder(
+    name = "Mac Builder Next",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "bld",
+    ),
+    cores = None,
+    os = None,
+)
+
+ci.thin_tester(
+    name = "Mac11.0 Tests",
+    mastername = "chromium.fyi",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "11.0",
+    ),
+    triggered_by = ["Mac Builder Next"],
+)
+
+ci.fyi_mac_builder(
+    name = "Mac deterministic",
+    console_view_entry = ci.console_view_entry(
+        category = "deterministic|mac",
+        short_name = "rel",
+    ),
+    cores = None,
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+)
+
+ci.fyi_mac_builder(
+    name = "Mac deterministic (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "deterministic|mac",
+        short_name = "dbg",
+    ),
+    cores = None,
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+)
+
+ci.fyi_mac_builder(
+    name = "mac-hermetic-upgrade-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "herm",
+    ),
+    cores = 8,
+)
+
+ci.fyi_mac_builder(
+    name = "mac-mojo-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "mac",
+    ),
+    os = os.MAC_ANY,
+)
+
+ci.fyi_windows_builder(
+    name = "Win10 Tests x64 1803",
+    console_view_entry = ci.console_view_entry(
+        category = "win10|1803",
+    ),
+    goma_backend = None,
+    main_console_view = None,
+    os = os.WINDOWS_10,
+    triggered_by = ["ci/Win x64 Builder"],
+)
+
+ci.fyi_windows_builder(
+    name = "Win10 Tests x64 1909",
+    console_view_entry = ci.console_view_entry(
+        category = "win10|1909",
+    ),
+    goma_backend = None,
+    main_console_view = None,
+    os = os.WINDOWS_10,
+    triggered_by = ["ci/Win x64 Builder"],
+)
+
+ci.fyi_windows_builder(
+    name = "Win 10 Fast Ring",
+    console_view_entry = ci.console_view_entry(
+        category = "win10",
+    ),
+    os = os.WINDOWS_10,
+    notifies = ["Win 10 Fast Ring"],
+)
+
+ci.fyi_windows_builder(
+    name = "win32-arm64-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "win32|arm64",
+    ),
+    cpu = cpu.X86,
+    goma_jobs = goma.jobs.J150,
+)
+
+ci.fyi_windows_builder(
+    name = "win-annotator-rel",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "network|traffic|annotations",
+        short_name = "win",
+    ),
+    execution_timeout = 16 * time.hour,
+    notifies = ["annotator-rel"],
+)
+
+ci.fyi_windows_builder(
+    name = "Mojo Windows",
+    console_view_entry = ci.console_view_entry(
+        category = "mojo",
+        short_name = "win",
+    ),
+)
+
 ci.gpu_builder(
     name = "Android Release (Nexus 5X)",
     branch_selector = branches.STANDARD_RELEASES,
@@ -914,6 +2995,14 @@
 )
 
 ci.gpu_builder(
+    name = "GPU Linux Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux",
+    ),
+    tree_closing = False,
+)
+
+ci.gpu_builder(
     name = "GPU Mac Builder",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -926,6 +3015,16 @@
 )
 
 ci.gpu_builder(
+    name = "GPU Mac Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac",
+    ),
+    cores = None,
+    os = os.MAC_ANY,
+    tree_closing = False,
+)
+
+ci.gpu_builder(
     name = "GPU Win x64 Builder",
     branch_selector = branches.STANDARD_RELEASES,
     builderless = True,
@@ -937,6 +3036,25 @@
     os = os.WINDOWS_ANY,
 )
 
+ci.gpu_builder(
+    name = "GPU Win x64 Builder (dbg)",
+    builderless = True,
+    console_view_entry = ci.console_view_entry(
+        category = "Windows",
+    ),
+    os = os.WINDOWS_ANY,
+    tree_closing = False,
+)
+
+ci.gpu_thin_tester(
+    name = "Linux Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux",
+    ),
+    triggered_by = ["GPU Linux Builder (dbg)"],
+    tree_closing = False,
+)
+
 ci.gpu_thin_tester(
     name = "Linux Release (NVIDIA)",
     branch_selector = branches.STANDARD_RELEASES,
@@ -952,6 +3070,15 @@
 )
 
 ci.gpu_thin_tester(
+    name = "Mac Debug (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac",
+    ),
+    triggered_by = ["GPU Mac Builder (dbg)"],
+    tree_closing = False,
+)
+
+ci.gpu_thin_tester(
     name = "Mac Release (Intel)",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -963,6 +3090,15 @@
 )
 
 ci.gpu_thin_tester(
+    name = "Mac Retina Debug (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac",
+    ),
+    triggered_by = ["GPU Mac Builder (dbg)"],
+    tree_closing = False,
+)
+
+ci.gpu_thin_tester(
     name = "Mac Retina Release (AMD)",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -974,6 +3110,15 @@
 )
 
 ci.gpu_thin_tester(
+    name = "Win10 x64 Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows",
+    ),
+    triggered_by = ["GPU Win x64 Builder (dbg)"],
+    tree_closing = False,
+)
+
+ci.gpu_thin_tester(
     name = "Win10 x64 Release (NVIDIA)",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -984,6 +3129,749 @@
     triggered_by = [builder_name("GPU Win x64 Builder")],
 )
 
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI 32 Vk Release (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|vk|Q32",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI 32 dEQP Vk Release (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|dqp|vk|Q32",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI 64 Perf (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|Perf|Q64",
+        short_name = "P2",
+    ),
+    cores = 2,
+    triggered_by = ["GPU FYI Perf Android 64 Builder"],
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI 64 Vk Release (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|vk|Q64",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI 64 dEQP Vk Release (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|dqp|vk|Q64",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (NVIDIA Shield TV)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|N64|NVDA",
+        short_name = "STV",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Nexus 5)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|L32",
+        short_name = "N5",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Nexus 5X)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|M64|QCOM",
+        short_name = "N5X",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Nexus 6)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|L32",
+        short_name = "N6",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Nexus 6P)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|M64|QCOM",
+        short_name = "N6P",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Nexus 9)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|M64|NVDA",
+        short_name = "N9",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI Release (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|P32|QCOM",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI SkiaRenderer GL (Nexus 5X)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|skgl|M64",
+        short_name = "N5X",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI SkiaRenderer Vulkan (Pixel 2)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|skv|P32",
+        short_name = "P2",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Android FYI dEQP Release (Nexus 5X)",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|dqp|M64",
+        short_name = "N5X",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "ChromeOS FYI Release (amd64-generic)",
+    console_view_entry = ci.console_view_entry(
+        category = "ChromeOS|amd64|generic",
+        short_name = "x64",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "ChromeOS FYI Release (kevin)",
+    console_view_entry = ci.console_view_entry(
+        category = "ChromeOS|arm|kevin",
+        short_name = "kvn",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "GPU FYI Linux Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Builder",
+        short_name = "rel",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "GPU FYI Linux Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Builder",
+        short_name = "dbg",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "GPU FYI Linux Ozone Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Builder",
+        short_name = "ozn",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "GPU FYI Linux dEQP Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Builder",
+        short_name = "dqp",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "GPU FYI Perf Android 64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Android|Perf|Builder",
+        short_name = "64",
+    ),
+)
+
+ci.gpu_fyi_linux_builder(
+    name = "Linux FYI GPU TSAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux",
+        short_name = "tsn",
+    ),
+)
+
+# Builder + tester.
+ci.gpu_fyi_linux_builder(
+    name = "Linux FYI SkiaRenderer Dawn Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "skd",
+    ),
+)
+
+ci.gpu_fyi_mac_builder(
+    name = "Mac FYI arm64 Release (Apple DTK)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac",
+        short_name = "dtk",
+    ),
+    cores = 8,
+)
+
+ci.gpu_fyi_mac_builder(
+    name = "Mac FYI GPU ASAN Release",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac",
+        short_name = "asn",
+    ),
+)
+
+ci.gpu_fyi_mac_builder(
+    name = "GPU FYI Mac Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Builder",
+        short_name = "rel",
+    ),
+)
+
+ci.gpu_fyi_mac_builder(
+    name = "GPU FYI Mac Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Builder",
+        short_name = "dbg",
+    ),
+)
+
+ci.gpu_fyi_mac_builder(
+    name = "GPU FYI Mac dEQP Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Builder",
+        short_name = "dqp",
+    ),
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Nvidia",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Linux Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Experimental Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Experimental Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Nvidia",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Ozone (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "ozn",
+    ),
+    triggered_by = ["GPU FYI Linux Ozone Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Release (AMD R7 240)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|AMD",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI Release (Intel UHD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "uhd",
+    ),
+    # TODO(https://crbug.com/986939): Remove this increased timeout once more
+    # devices are added.
+    execution_timeout = 18 * time.hour,
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI SkiaRenderer Vulkan (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "skv",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI SkiaRenderer Vulkan (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Nvidia",
+        short_name = "skv",
+    ),
+    triggered_by = ["GPU FYI Linux Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI dEQP Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Intel",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Linux dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Linux FYI dEQP Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Linux|Nvidia",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Linux dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Debug (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Intel",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Mac Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Experimental Release (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Intel",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Experimental Retina Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|AMD|Retina",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Experimental Retina Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Nvidia",
+        short_name = "exp",
+    ),
+    # This bot has one machine backing its tests at the moment.
+    # If it gets more, this can be removed.
+    # See crbug.com/853307 for more context.
+    execution_timeout = 12 * time.hour,
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Release (Intel)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Intel",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Retina Debug (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|AMD|Retina",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Mac Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Retina Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Nvidia",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Mac Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Retina Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|AMD|Retina",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI Retina Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI dEQP Release AMD",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|AMD",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Mac dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac FYI dEQP Release Intel",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|Intel",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Mac dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Mac Pro FYI Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Mac|AMD|Pro",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Mac Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia|dx12vk",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Win x64 DX12 Vulkan Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 DX12 Vulkan Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia|dx12vk",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win x64 DX12 Vulkan Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Exp Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Intel",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Exp Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "exp",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release (AMD RX 550)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|AMD",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Intel",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release (Intel UHD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Intel",
+        short_name = "uhd",
+    ),
+    # TODO(https://crbug.com/986939): Remove this increased timeout once
+    # more devices are added.
+    execution_timeout = 18 * time.hour,
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "gtx",
+    ),
+    execution_timeout = 18 * time.hour,
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 Release XR Perf (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "xr",
+    ),
+    triggered_by = ["GPU FYI XR Win x64 Builder"],
+)
+
+# Builder + tester.
+ci.gpu_fyi_windows_builder(
+    name = "Win10 FYI x64 SkiaRenderer Dawn Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "skd",
+    ),
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 SkiaRenderer GL (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "skgl",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 dEQP Release (Intel HD 630)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Intel",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x64 dEQP Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x64|Nvidia",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win10 FYI x86 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|10|x86|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI Debug (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x86|AMD",
+        short_name = "dbg",
+    ),
+    triggered_by = ["GPU FYI Win Builder (dbg)"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x86|AMD",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x86|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI dEQP Release (AMD)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x86|AMD",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Win dEQP Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI x64 Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x64|Nvidia",
+        short_name = "rel",
+    ),
+    triggered_by = ["GPU FYI Win x64 Builder"],
+)
+
+ci.gpu_fyi_thin_tester(
+    name = "Win7 FYI x64 dEQP Release (NVIDIA)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|7|x64|Nvidia",
+        short_name = "dqp",
+    ),
+    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|Release",
+        short_name = "x86",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|Debug",
+        short_name = "x86",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win dEQP Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|dEQP",
+        short_name = "x86",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win x64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|Release",
+        short_name = "x64",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win x64 Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|Debug",
+        short_name = "x64",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win x64 dEQP Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|dEQP",
+        short_name = "x64",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win x64 DX12 Vulkan Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|dx12vk",
+        short_name = "rel",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI Win x64 DX12 Vulkan Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|dx12vk",
+        short_name = "dbg",
+    ),
+)
+
+ci.gpu_fyi_windows_builder(
+    name = "GPU FYI XR Win x64 Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "Windows|Builder|XR",
+        short_name = "x64",
+    ),
+)
+
+ci.linux_builder(
+    name = "Cast Audio Linux",
+    console_view_entry = ci.console_view_entry(
+        category = "cast",
+        short_name = "aud",
+    ),
+    main_console_view = "main",
+    ssd = True,
+)
+
 ci.linux_builder(
     name = "Cast Linux",
     branch_selector = branches.STANDARD_RELEASES,
@@ -997,6 +3885,46 @@
 )
 
 ci.linux_builder(
+    name = "Deterministic Fuchsia (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|x64",
+        short_name = "det",
+    ),
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    goma_jobs = None,
+    main_console_view = "main",
+)
+
+ci.linux_builder(
+    name = "Deterministic Linux",
+    console_view_entry = ci.console_view_entry(
+        category = "release",
+        short_name = "det",
+    ),
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    main_console_view = "main",
+    # Set tree_closing to false to disable the defaualt tree closer, which
+    # filters by step name, and instead enable tree closing for any step
+    # failure.
+    tree_closing = False,
+    extra_notifies = ["Deterministic Linux", "close-on-any-step-failure"],
+)
+
+ci.linux_builder(
+    name = "Deterministic Linux (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "debug|builder",
+        short_name = "det",
+    ),
+    cores = 32,
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    main_console_view = "main",
+)
+
+ci.linux_builder(
     name = "Fuchsia ARM64",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -1021,6 +3949,17 @@
 )
 
 ci.linux_builder(
+    name = "Leak Detection Linux",
+    console_view = "chromium.fyi",
+    console_view_entry = ci.console_view_entry(
+        category = "linux",
+        short_name = "lk",
+    ),
+    notifies = [],
+    tree_closing = False,
+)
+
+ci.linux_builder(
     name = "Linux Builder",
     branch_selector = branches.STANDARD_RELEASES,
     # TODO(https://crbug.com/1109276) Once support for mastername is removed, do
@@ -1046,6 +3985,15 @@
 )
 
 ci.linux_builder(
+    name = "Linux Builder (dbg)(32)",
+    console_view_entry = ci.console_view_entry(
+        category = "debug|builder",
+        short_name = "32",
+    ),
+    main_console_view = "main",
+)
+
+ci.linux_builder(
     name = "Linux Tests",
     branch_selector = branches.STANDARD_RELEASES,
     # TODO(https://crbug.com/1109276) Once support for mastername is removed, do
@@ -1090,6 +4038,15 @@
 )
 
 ci.linux_builder(
+    name = "Network Service Linux",
+    console_view_entry = ci.console_view_entry(
+        category = "release",
+        short_name = "nsl",
+    ),
+    main_console_view = "main",
+)
+
+ci.linux_builder(
     name = "fuchsia-x64-cast",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -1106,6 +4063,35 @@
 )
 
 ci.linux_builder(
+    name = "fuchsia-x64-dbg",
+    console_view_entry = ci.console_view_entry(
+        category = "fuchsia|x64",
+        short_name = "dbg",
+    ),
+    main_console_view = "main",
+    extra_notifies = ["cr-fuchsia"],
+)
+
+ci.linux_builder(
+    name = "linux-bfcache-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "bfcache",
+        short_name = "bfc",
+    ),
+    main_console_view = "main",
+)
+
+ci.linux_builder(
+    name = "linux-gcc-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "release",
+        short_name = "gcc",
+    ),
+    goma_backend = None,
+    main_console_view = "main",
+)
+
+ci.linux_builder(
     name = "linux-ozone-rel",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -1160,6 +4146,24 @@
     triggered_by = [builder_name("linux-ozone-rel")],
 )
 
+ci.linux_builder(
+    name = "linux-trusty-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "release",
+        short_name = "tru",
+    ),
+    main_console_view = "main",
+    os = os.LINUX_TRUSTY,
+)
+
+ci.linux_builder(
+    name = "metadata-exporter",
+    executable = "recipe:chromium_export_metadata",
+    service_account = "component-mapping-updater@chops-service-accounts.iam.gserviceaccount.com",
+    notifies = ["metadata-mapping"],
+    tree_closing = False,
+)
+
 ci.mac_builder(
     name = "Mac Builder",
     branch_selector = branches.STANDARD_RELEASES,
@@ -1288,6 +4292,17 @@
 )
 
 ci.mac_ios_builder(
+    name = "ios-device",
+    console_view_entry = ci.console_view_entry(
+        category = "ios|default",
+        short_name = "dev",
+    ),
+    # We don't have necessary capacity to run this configuration in CQ, but it
+    # is part of the main waterfall
+    main_console_view = "main",
+)
+
+ci.mac_ios_builder(
     name = "ios-simulator",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -1309,6 +4324,39 @@
     main_console_view = settings.main_console_name,
 )
 
+ci.mac_ios_builder(
+    name = "ios-simulator-noncq",
+    caches = [
+        xcode_cache.x12a8189n,
+    ],
+    console_view_entry = ci.console_view_entry(
+        category = "ios|default",
+        short_name = "non",
+    ),
+    # We don't have necessary capacity to run this configuration in CQ, but it
+    # is part of the main waterfall
+    main_console_view = "main",
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+ci.memory_builder(
+    name = "Android CFI",
+    # TODO(https://crbug.com/1008094) When this builder is not consistently
+    # failing, remove the console_view value
+    console_view = "chromium.android.fyi",
+    console_view_entry = ci.console_view_entry(
+        category = "memory",
+        short_name = "cfi",
+    ),
+    cores = 32,
+    # TODO(https://crbug.com/919430) Remove the larger timeout once compile
+    # times have been brought down to reasonable level
+    execution_timeout = 4 * time.hour + 30 * time.minute,
+    tree_closing = False,
+)
+
 ci.memory_builder(
     name = "Linux ASan LSan Builder",
     branch_selector = branches.STANDARD_RELEASES,
@@ -1357,6 +4405,97 @@
 )
 
 ci.memory_builder(
+    name = "Linux CFI",
+    console_view_entry = ci.console_view_entry(
+        category = "cfi",
+        short_name = "lnx",
+    ),
+    cores = 32,
+    # TODO(thakis): Remove once https://crbug.com/927738 is resolved.
+    execution_timeout = 4 * time.hour,
+    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux Chromium OS ASan LSan Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "cros|asan",
+        short_name = "bld",
+    ),
+    # TODO(crbug.com/1030593): Builds take more than 3 hours sometimes. Remove
+    # once the builds are faster.
+    execution_timeout = 6 * time.hour,
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux Chromium OS ASan LSan Tests (1)",
+    console_view_entry = ci.console_view_entry(
+        category = "cros|asan",
+        short_name = "tst",
+    ),
+    triggered_by = ["Linux Chromium OS ASan LSan Builder"],
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux ChromiumOS MSan Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "cros|msan",
+        short_name = "bld",
+    ),
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux ChromiumOS MSan Tests",
+    console_view_entry = ci.console_view_entry(
+        category = "cros|msan",
+        short_name = "tst",
+    ),
+    triggered_by = ["Linux ChromiumOS MSan Builder"],
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux MSan Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|msan",
+        short_name = "bld",
+    ),
+    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Linux MSan Tests",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|msan",
+        short_name = "tst",
+    ),
+    triggered_by = ["Linux MSan Builder"],
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "Mac ASan 64 Builder",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "bld",
+    ),
+    goma_debug = True,  # TODO(hinoka): Remove this after debugging.
+    goma_jobs = None,
+    cores = None,  # Swapping between 8 and 24
+    main_console_view = "main",
+    os = os.MAC_DEFAULT,
+    triggering_policy = scheduler.greedy_batching(
+        max_concurrent_invocations = 2,
+    ),
+)
+
+ci.memory_builder(
     name = "Linux TSan Tests",
     branch_selector = branches.STANDARD_RELEASES,
     console_view_entry = ci.console_view_entry(
@@ -1368,6 +4507,261 @@
     main_console_view = settings.main_console_name,
 )
 
+ci.memory_builder(
+    name = "Mac ASan 64 Tests (1)",
+    builderless = False,
+    console_view_entry = ci.console_view_entry(
+        category = "mac",
+        short_name = "tst",
+    ),
+    main_console_view = "main",
+    os = os.MAC_DEFAULT,
+    triggered_by = ["Mac ASan 64 Builder"],
+)
+
+ci.memory_builder(
+    name = "WebKit Linux ASAN",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|webkit",
+        short_name = "asn",
+    ),
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "WebKit Linux Leak",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|webkit",
+        short_name = "lk",
+    ),
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "WebKit Linux MSAN",
+    console_view_entry = ci.console_view_entry(
+        category = "linux|webkit",
+        short_name = "msn",
+    ),
+    main_console_view = "main",
+)
+
+ci.memory_builder(
+    name = "android-asan",
+    console_view_entry = ci.console_view_entry(
+        category = "android",
+        short_name = "asn",
+    ),
+    main_console_view = "main",
+    tree_closing = False,
+)
+
+ci.memory_builder(
+    name = "win-asan",
+    console_view_entry = ci.console_view_entry(
+        category = "win",
+        short_name = "asn",
+    ),
+    cores = 32,
+    builderless = True,
+    main_console_view = "main",
+    os = os.WINDOWS_DEFAULT,
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-chromium-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "Chromium|Linux",
+        short_name = "x64",
+    ),
+    pinned = False,
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-tot-angle-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT ANGLE|Linux",
+        short_name = "x64",
+    ),
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-tot-angle-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT ANGLE|Linux",
+        short_name = "x86",
+    ),
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-tot-swiftshader-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT SwiftShader|Linux",
+        short_name = "x64",
+    ),
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-tot-swiftshader-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT SwiftShader|Linux",
+        short_name = "x86",
+    ),
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "DEPS|Linux",
+        short_name = "x64",
+    ),
+    pinned = False,
+)
+
+ci.swangle_linux_builder(
+    name = "linux-swangle-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "DEPS|Linux",
+        short_name = "x86",
+    ),
+    pinned = False,
+)
+
+ci.swangle_mac_builder(
+    name = "mac-swangle-chromium-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "Chromium|Mac",
+        short_name = "x64",
+    ),
+    pinned = False,
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-chromium-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "Chromium|Windows",
+        short_name = "x86",
+    ),
+    pinned = False,
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-tot-angle-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT ANGLE|Windows",
+        short_name = "x64",
+    ),
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-tot-angle-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT ANGLE|Windows",
+        short_name = "x86",
+    ),
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-tot-swiftshader-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT SwiftShader|Windows",
+        short_name = "x64",
+    ),
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-tot-swiftshader-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "ToT SwiftShader|Windows",
+        short_name = "x86",
+    ),
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-x64",
+    console_view_entry = ci.console_view_entry(
+        category = "DEPS|Windows",
+        short_name = "x64",
+    ),
+    pinned = False,
+)
+
+ci.swangle_windows_builder(
+    name = "win-swangle-x86",
+    console_view_entry = ci.console_view_entry(
+        category = "DEPS|Windows",
+        short_name = "x86",
+    ),
+    pinned = False,
+)
+
+ci.win_builder(
+    name = "WebKit Win10",
+    console_view_entry = ci.console_view_entry(
+        category = "misc",
+        short_name = "wbk",
+    ),
+    main_console_view = "main",
+    triggered_by = ["Win Builder"],
+)
+
+ci.win_builder(
+    name = "Win Builder",
+    console_view_entry = ci.console_view_entry(
+        category = "release|builder",
+        short_name = "32",
+    ),
+    cores = 32,
+    main_console_view = "main",
+    os = os.WINDOWS_ANY,
+)
+
+ci.win_builder(
+    name = "Win x64 Builder (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "debug|builder",
+        short_name = "64",
+    ),
+    cores = 32,
+    builderless = True,
+    main_console_view = "main",
+    os = os.WINDOWS_ANY,
+)
+
+ci.win_builder(
+    name = "Win10 Tests x64 (dbg)",
+    console_view_entry = ci.console_view_entry(
+        category = "debug|tester",
+        short_name = "10",
+    ),
+    main_console_view = "main",
+    triggered_by = ["Win x64 Builder (dbg)"],
+    # Too flaky. See crbug.com/876224 for more details.
+    tree_closing = False,
+)
+
+ci.win_builder(
+    name = "Win7 (32) Tests",
+    console_view_entry = ci.console_view_entry(
+        category = "release|tester",
+        short_name = "32",
+    ),
+    main_console_view = "main",
+    os = os.WINDOWS_7,
+    triggered_by = ["Win Builder"],
+)
+
+ci.win_builder(
+    name = "Win7 Tests (1)",
+    console_view_entry = ci.console_view_entry(
+        category = "release|tester",
+        short_name = "32",
+    ),
+    main_console_view = "main",
+    os = os.WINDOWS_7,
+    triggered_by = ["Win Builder"],
+)
+
 ci.win_builder(
     name = "Win7 Tests (dbg)(1)",
     branch_selector = branches.STANDARD_RELEASES,
@@ -1431,3 +4825,15 @@
     main_console_view = settings.main_console_name,
     triggered_by = [builder_name("Win x64 Builder")],
 )
+
+ci.win_builder(
+    name = "Windows deterministic",
+    console_view_entry = ci.console_view_entry(
+        category = "misc",
+        short_name = "det",
+    ),
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+    goma_jobs = goma.jobs.J150,
+    main_console_view = "main",
+)
diff --git a/infra/config/subprojects/chromium/master-only/consoles/android.packager.star b/infra/config/subprojects/chromium/consoles/android.packager.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/consoles/android.packager.star
rename to infra/config/subprojects/chromium/consoles/android.packager.star
diff --git a/infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star b/infra/config/subprojects/chromium/consoles/luci.chromium.try.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/consoles/luci.chromium.try.star
rename to infra/config/subprojects/chromium/consoles/luci.chromium.try.star
diff --git a/infra/config/subprojects/chromium/master-only/consoles/metadata.exporter.star b/infra/config/subprojects/chromium/consoles/metadata.exporter.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/consoles/metadata.exporter.star
rename to infra/config/subprojects/chromium/consoles/metadata.exporter.star
diff --git a/infra/config/subprojects/chromium/master-only/consoles/sheriff.ios.star b/infra/config/subprojects/chromium/consoles/sheriff.ios.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/consoles/sheriff.ios.star
rename to infra/config/subprojects/chromium/consoles/sheriff.ios.star
diff --git a/infra/config/subprojects/chromium/master-only/fallback-cq.star b/infra/config/subprojects/chromium/fallback-cq.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/fallback-cq.star
rename to infra/config/subprojects/chromium/fallback-cq.star
diff --git a/infra/config/subprojects/chromium/master-only/gpu.try.star b/infra/config/subprojects/chromium/gpu.try.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/gpu.try.star
rename to infra/config/subprojects/chromium/gpu.try.star
diff --git a/infra/config/subprojects/chromium/master-only/README.md b/infra/config/subprojects/chromium/master-only/README.md
deleted file mode 100644
index d44be8e7..0000000
--- a/infra/config/subprojects/chromium/master-only/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-Definitions of LUCI entities that only exist for the master branch.
-
-* **consoles**
-  * manually curated consoles for chromium subproject builders
-* **ci.star**
-  * builders that do post-submit testing against the master branch
-  * when new milestones are created, milestone-specific versions of the builders
-  will not be created
-* **try.star**, **gpu.try.star**, **swangle.try.star**
-  * builders that do pre-submit testing against the master branch
-  * when new milestones are created, milestone-specific versions of the builders
-  will not be created
diff --git a/infra/config/subprojects/chromium/master-only/ci.star b/infra/config/subprojects/chromium/master-only/ci.star
deleted file mode 100644
index 576fdeed9..0000000
--- a/infra/config/subprojects/chromium/master-only/ci.star
+++ /dev/null
@@ -1,3427 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-load("//lib/builders.star", "cpu", "goma", "os", "xcode_cache")
-load("//lib/ci.star", "ci")
-load("//project.star", "settings")
-
-# Execute the versioned files to define all of the per-branch entities
-# (bucket, builders, console, poller, etc.)
-exec("../versioned/m85/buckets/ci.star")
-
-ci.set_defaults(
-    settings,
-    add_to_console_view = True,
-)
-
-# *** After this point everything is trunk only ***
-
-# The chromium.clang console includes some entries for builders from the chrome project
-[luci.console_view_entry(
-    builder = "chrome:ci/{}".format(name),
-    console_view = "chromium.clang",
-    category = category,
-    short_name = short_name,
-) for name, category, short_name in (
-    ("ToTLinuxOfficial", "ToT Linux", "ofi"),
-    ("ToTMacOfficial", "ToT Mac", "ofi"),
-    ("ToTWin", "ToT Windows", "rel"),
-    ("ToTWin64", "ToT Windows|x64", "rel"),
-    ("ToTWinOfficial", "ToT Windows", "ofi"),
-    ("ToTWinThinLTO64", "ToT Windows|x64", "lto"),
-    ("clang-tot-device", "iOS|internal", "dev"),
-)]
-
-# The main console includes some entries for builders from the chrome project
-[luci.console_view_entry(
-    builder = "chrome:ci/{}".format(name),
-    console_view = "main",
-    category = "chrome",
-    short_name = short_name,
-) for name, short_name in (
-    ("linux-chromeos-chrome", "cro"),
-    ("linux-chrome", "lnx"),
-    ("mac-chrome", "mac"),
-    ("win-chrome", "win"),
-    ("win64-chrome", "win"),
-)]
-
-# Builders are sorted first lexicographically by the function used to define
-# them, then lexicographically by their name
-
-ci.builder(
-    name = "android-avd-packager",
-    executable = "recipe:android/avd_packager",
-    properties = {
-        "avd_configs": [
-            "tools/android/avd/proto/creation/generic_android23.textpb",
-            "tools/android/avd/proto/creation/generic_android28.textpb",
-            "tools/android/avd/proto/creation/generic_android29.textpb",
-            "tools/android/avd/proto/creation/generic_playstore_android28.textpb",
-        ],
-    },
-    schedule = "0 7 * * 0 *",
-    service_account = "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com",
-    triggered_by = [],
-)
-
-ci.builder(
-    name = "android-sdk-packager",
-    executable = "recipe:android/sdk_packager",
-    schedule = "0 7 * * 0 *",
-    service_account = "chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com",
-    triggered_by = [],
-    properties = {
-        # We still package part of build-tools;25.0.2 to support
-        # http://bit.ly/2KNUygZ
-        "packages": [
-            {
-                "sdk_package_name": "build-tools;25.0.2",
-                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/25.0.2.yaml",
-            },
-            {
-                "sdk_package_name": "build-tools;29.0.2",
-                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/29.0.2.yaml",
-            },
-            {
-                "sdk_package_name": "build-tools;30.0.1",
-                "cipd_yaml": "third_party/android_sdk/cipd/build-tools/30.0.1.yaml",
-            },
-            {
-                "sdk_package_name": "cmdline-tools;latest",
-                "cipd_yaml": "third_party/android_sdk/cipd/cmdline-tools.yaml",
-            },
-            {
-                "sdk_package_name": "emulator",
-                "cipd_yaml": "third_party/android_sdk/cipd/emulator.yaml",
-            },
-            {
-                "sdk_package_name": "extras;google;gcm",
-                "cipd_yaml": "third_party/android_sdk/cipd/extras/google/gcm.yaml",
-            },
-            {
-                "sdk_package_name": "patcher;v4",
-                "cipd_yaml": "third_party/android_sdk/cipd/patcher/v4.yaml",
-            },
-            {
-                "sdk_package_name": "platforms;android-29",
-                "cipd_yaml": "third_party/android_sdk/cipd/platforms/android-29.yaml",
-            },
-            {
-                "sdk_package_name": "platforms;android-30",
-                "cipd_yaml": "third_party/android_sdk/cipd/platforms/android-30.yaml",
-            },
-            {
-                "sdk_package_name": "platform-tools",
-                "cipd_yaml": "third_party/android_sdk/cipd/platform-tools.yaml",
-            },
-            {
-                "sdk_package_name": "sources;android-29",
-                "cipd_yaml": "third_party/android_sdk/cipd/sources/android-29.yaml",
-            },
-            # Not yet available as R is not released to AOSP.
-            #{
-            #    'sdk_package_name': 'sources;android-30',
-            #    'cipd_yaml': 'third_party/android_sdk/cipd/sources/android-30.yaml'
-            #},
-            {
-                "sdk_package_name": "system-images;android-29;google_apis;x86",
-                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-29/google_apis/x86.yaml",
-            },
-            {
-                "sdk_package_name": "system-images;android-29;google_apis_playstore;x86",
-                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-29/google_apis_playstore/x86.yaml",
-            },
-            {
-                "sdk_package_name": "system-images;android-30;google_apis;x86",
-                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-30/google_apis/x86.yaml",
-            },
-            {
-                "sdk_package_name": "system-images;android-30;google_apis_playstore;x86",
-                "cipd_yaml": "third_party/android_sdk/cipd/system_images/android-30/google_apis_playstore/x86.yaml",
-            },
-        ],
-    },
-)
-
-ci.android_builder(
-    name = "Android ASAN (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "builder|arm",
-        short_name = "san",
-    ),
-    # Higher build timeout since dbg ASAN builds can take a while on a clobber
-    # build.
-    execution_timeout = 4 * time.hour,
-    tree_closing = True,
-)
-
-ci.android_builder(
-    name = "Android WebView L (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "tester|webview",
-        short_name = "L",
-    ),
-    triggered_by = ["ci/Android arm Builder (dbg)"],
-)
-
-ci.android_builder(
-    name = "Deterministic Android",
-    console_view_entry = ci.console_view_entry(
-        category = "builder|det",
-        short_name = "rel",
-    ),
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    notifies = ["Deterministic Android"],
-    tree_closing = True,
-)
-
-ci.android_builder(
-    name = "Deterministic Android (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "builder|det",
-        short_name = "dbg",
-    ),
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    notifies = ["Deterministic Android"],
-    tree_closing = True,
-)
-
-ci.android_builder(
-    name = "Lollipop Phone Tester",
-    console_view_entry = ci.console_view_entry(
-        category = "tester|phone",
-        short_name = "L",
-    ),
-    # We have limited phone capacity and thus limited ability to run
-    # tests in parallel, hence the high timeout.
-    execution_timeout = 6 * time.hour,
-    triggered_by = ["ci/Android arm Builder (dbg)"],
-)
-
-ci.android_builder(
-    name = "Lollipop Tablet Tester",
-    console_view_entry = ci.console_view_entry(
-        category = "tester|tablet",
-        short_name = "L",
-    ),
-    # We have limited tablet capacity and thus limited ability to run
-    # tests in parallel, hence the high timeout.
-    execution_timeout = 20 * time.hour,
-    triggered_by = ["ci/Android arm Builder (dbg)"],
-)
-
-ci.android_builder(
-    name = "Marshmallow Tablet Tester",
-    console_view_entry = ci.console_view_entry(
-        category = "tester|tablet",
-        short_name = "M",
-    ),
-    # We have limited tablet capacity and thus limited ability to run
-    # tests in parallel, hence the high timeout.
-    execution_timeout = 12 * time.hour,
-    triggered_by = ["ci/Android arm Builder (dbg)"],
-)
-
-ci.android_builder(
-    name = "android-arm64-proguard-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "builder_tester|arm64",
-        short_name = "M proguard",
-    ),
-    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
-    execution_timeout = 6 * time.hour,
-)
-
-ci.android_builder(
-    name = "android-bfcache-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "bfcache",
-        short_name = "bfc",
-    ),
-)
-
-ci.android_builder(
-    name = "android-cronet-arm64-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|arm64",
-        short_name = "dbg",
-    ),
-    notifies = ["cronet"],
-)
-
-ci.android_builder(
-    name = "android-cronet-arm64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|arm64",
-        short_name = "rel",
-    ),
-    notifies = ["cronet"],
-)
-
-ci.android_builder(
-    name = "android-cronet-asan-arm-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|asan",
-    ),
-    notifies = ["cronet"],
-)
-
-# Runs on a specific machine with an attached phone
-ci.android_builder(
-    name = "android-cronet-marshmallow-arm64-perf-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|test|perf",
-        short_name = "m",
-    ),
-    cores = None,
-    cpu = None,
-    executable = "recipe:cronet",
-    notifies = ["cronet"],
-    os = os.ANDROID,
-)
-
-ci.android_builder(
-    name = "android-cronet-marshmallow-arm64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|test",
-        short_name = "m",
-    ),
-    notifies = ["cronet"],
-    triggered_by = ["android-cronet-arm64-rel"],
-)
-
-ci.android_builder(
-    name = "android-cronet-x86-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|x86",
-        short_name = "dbg",
-    ),
-    notifies = ["cronet"],
-)
-
-ci.android_builder(
-    name = "android-cronet-x86-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "cronet|x86",
-        short_name = "rel",
-    ),
-    notifies = ["cronet"],
-)
-
-ci.android_builder(
-    name = "android-incremental-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "tester|incremental",
-    ),
-)
-
-ci.android_builder(
-    name = "android-pie-x86-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "builder_tester|x86",
-        short_name = "P",
-    ),
-)
-
-ci.android_builder(
-    name = "android-10-arm64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "builder_tester|arm64",
-        short_name = "10",
-    ),
-)
-
-ci.android_builder(
-    name = "android-binary-size-generator",
-    executable = "recipe:binary_size_generator_tot",
-    console_view_entry = ci.console_view_entry(
-        category = "builder|other",
-        short_name = "size",
-    ),
-)
-
-ci.android_fyi_builder(
-    name = "Android WebLayer P FYI (rel)",
-    console_view_entry = ci.console_view_entry(
-        category = "weblayer",
-        short_name = "p-rel",
-    ),
-)
-
-ci.android_fyi_builder(
-    name = "android-weblayer-pie-x86-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "weblayer",
-        short_name = "p-x86-rel",
-    ),
-)
-
-ci.android_fyi_builder(
-    name = "Android WebView P FYI (rel)",
-    console_view_entry = ci.console_view_entry(
-        category = "webview",
-        short_name = "p-rel",
-    ),
-)
-
-ci.android_fyi_builder(
-    name = "android-marshmallow-x86-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "emulator|M|x86",
-        short_name = "rel",
-    ),
-    goma_jobs = goma.jobs.J150,
-)
-
-# TODO(hypan): remove this once there is no associated disabled tests
-ci.android_fyi_builder(
-    name = "android-pie-x86-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "emulator|P|x86",
-        short_name = "rel",
-    ),
-    goma_jobs = goma.jobs.J150,
-    schedule = "triggered",  # triggered manually via Scheduler UI
-)
-
-ci.chromium_builder(
-    name = "android-archive-dbg",
-    # Bump to 32 if needed.
-    console_view_entry = ci.console_view_entry(
-        category = "android",
-        short_name = "dbg",
-    ),
-    cores = 8,
-    main_console_view = "main",
-)
-
-ci.chromium_builder(
-    name = "android-archive-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "android",
-        short_name = "rel",
-    ),
-    cores = 32,
-    main_console_view = "main",
-)
-
-ci.chromium_builder(
-    name = "linux-archive-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-        short_name = "dbg",
-    ),
-    # Bump to 32 if needed.
-    cores = 8,
-    main_console_view = "main",
-)
-
-ci.chromium_builder(
-    name = "linux-archive-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-        short_name = "rel",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    notifies = ["linux-archive-rel"],
-)
-
-ci.chromium_builder(
-    name = "mac-archive-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "dbg",
-    ),
-    # Bump to 8 cores if needed.
-    cores = 4,
-    main_console_view = "main",
-    os = os.MAC_DEFAULT,
-)
-
-ci.chromium_builder(
-    name = "mac-archive-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "rel",
-    ),
-    main_console_view = "main",
-    os = os.MAC_DEFAULT,
-)
-
-ci.chromium_builder(
-    name = "win-archive-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "win|dbg",
-        short_name = "64",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    os = os.WINDOWS_DEFAULT,
-    tree_closing = False,
-)
-
-ci.chromium_builder(
-    name = "win-archive-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "win|rel",
-        short_name = "64",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    os = os.WINDOWS_DEFAULT,
-)
-
-ci.chromium_builder(
-    name = "win32-archive-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "win|dbg",
-        short_name = "32",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    os = os.WINDOWS_DEFAULT,
-    tree_closing = False,
-)
-
-ci.chromium_builder(
-    name = "win32-archive-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "win|rel",
-        short_name = "32",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    os = os.WINDOWS_DEFAULT,
-)
-
-ci.chromiumos_builder(
-    name = "Linux ChromiumOS Full",
-    console_view_entry = ci.console_view_entry(
-        category = "default",
-        short_name = "ful",
-    ),
-    main_console_view = "main",
-)
-
-ci.chromiumos_builder(
-    name = "chromeos-amd64-generic-asan-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "simple|release|x64",
-        short_name = "asn",
-    ),
-    main_console_view = "main",
-)
-
-ci.chromiumos_builder(
-    name = "chromeos-amd64-generic-cfi-thin-lto-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "simple|release|x64",
-        short_name = "cfi",
-    ),
-    main_console_view = "main",
-)
-
-ci.chromiumos_builder(
-    name = "chromeos-arm-generic-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "simple|debug",
-        short_name = "arm",
-    ),
-    main_console_view = "main",
-)
-
-ci.chromiumos_builder(
-    name = "chromeos-kevin-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "simple|release",
-        short_name = "kvn",
-    ),
-    main_console_view = "main",
-)
-
-ci.clang_builder(
-    name = "CFI Linux CF",
-    goma_backend = goma.backend.RBE_PROD,
-    console_view_entry = ci.console_view_entry(
-        category = "CFI|Linux",
-        short_name = "CF",
-    ),
-    notifies = ["CFI Linux"],
-)
-
-ci.clang_builder(
-    name = "CFI Linux ToT",
-    console_view_entry = ci.console_view_entry(
-        category = "CFI|Linux",
-        short_name = "ToT",
-    ),
-    notifies = ["CFI Linux"],
-)
-
-ci.clang_builder(
-    name = "CrWinAsan",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows|Asan",
-        short_name = "asn",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "CrWinAsan(dll)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows|Asan",
-        short_name = "dll",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTAndroid",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "rel",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroid (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "dbg",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroid x64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "x64",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroid64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "a64",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroidASan",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "asn",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroidCFI",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "cfi",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTAndroidOfficial",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Android",
-        short_name = "off",
-    ),
-)
-
-def clang_tot_linux_builder(short_name, category = "ToT Linux", **kwargs):
-    ci.clang_builder(
-        console_view_entry = ci.console_view_entry(
-            category = category,
-            short_name = short_name,
-        ),
-        notifies = [luci.notifier(
-            name = "ToT Linux notifier",
-            on_new_status = ["FAILURE"],
-            notify_emails = ["thomasanderson@chromium.org"],
-        )],
-        **kwargs
-    )
-
-clang_tot_linux_builder(
-    name = "ToTLinux",
-    short_name = "rel",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinux (dbg)",
-    short_name = "dbg",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxASan",
-    short_name = "asn",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxASanLibfuzzer",
-    # Requires a large disk, so has a machine specifically devoted to it
-    builderless = False,
-    short_name = "fuz",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxCoverage",
-    category = "ToT Code Coverage",
-    short_name = "linux",
-    executable = "recipe:chromium_clang_coverage_tot",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxMSan",
-    short_name = "msn",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxTSan",
-    short_name = "tsn",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxThinLTO",
-    short_name = "lto",
-)
-
-clang_tot_linux_builder(
-    name = "ToTLinuxUBSanVptr",
-    short_name = "usn",
-)
-
-ci.clang_builder(
-    name = "ToTWin(dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows",
-        short_name = "dbg",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWin(dll)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows",
-        short_name = "dll",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWin64(dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows|x64",
-        short_name = "dbg",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWin64(dll)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows|x64",
-        short_name = "dll",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWinASanLibfuzzer",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows|Asan",
-        short_name = "fuz",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWinCFI",
-    console_view_entry = ci.console_view_entry(
-        category = "CFI|Win",
-        short_name = "x86",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "ToTWinCFI64",
-    console_view_entry = ci.console_view_entry(
-        category = "CFI|Win",
-        short_name = "x64",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.clang_builder(
-    name = "UBSanVptr Linux",
-    console_view_entry = ci.console_view_entry(
-        short_name = "usn",
-    ),
-    goma_backend = goma.backend.RBE_PROD,
-)
-
-ci.clang_builder(
-    name = "linux-win_cross-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Windows",
-        short_name = "lxw",
-    ),
-)
-
-ci.clang_builder(
-    name = "ToTiOS",
-    caches = [xcode_cache.x11e146],
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|public",
-        short_name = "sim",
-    ),
-    cores = None,
-    os = os.MAC_10_14,
-    properties = {
-        "xcode_build_version": "11e146",
-    },
-    ssd = True,
-)
-
-ci.clang_builder(
-    name = "ToTiOSDevice",
-    caches = [xcode_cache.x11e146],
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|public",
-        short_name = "dev",
-    ),
-    cores = None,
-    os = os.MAC_10_14,
-    properties = {
-        "xcode_build_version": "11e146",
-    },
-    ssd = True,
-)
-
-ci.clang_mac_builder(
-    name = "ToTMac",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Mac",
-        short_name = "rel",
-    ),
-)
-
-ci.clang_mac_builder(
-    name = "ToTMac (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Mac",
-        short_name = "dbg",
-    ),
-)
-
-ci.clang_mac_builder(
-    name = "ToTMacASan",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Mac",
-        short_name = "asn",
-    ),
-)
-
-ci.clang_mac_builder(
-    name = "ToTMacCoverage",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT Code Coverage",
-        short_name = "mac",
-    ),
-    executable = "recipe:chromium_clang_coverage_tot",
-)
-
-ci.dawn_builder(
-    name = "Dawn Linux x64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Linux|Builder",
-        short_name = "x64",
-    ),
-)
-
-ci.dawn_builder(
-    name = "Dawn Linux x64 Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Linux|Intel",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Linux x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Linux x64 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Linux|Nvidia",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Linux x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Mac x64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Mac|Builder",
-        short_name = "x64",
-    ),
-    builderless = False,
-    cores = None,
-    os = os.MAC_ANY,
-)
-
-ci.dawn_builder(
-    name = "Dawn Mac x64 Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Mac|AMD",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Mac x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Mac x64 Release (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Mac|Intel",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Mac x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x86 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Builder",
-        short_name = "x86",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Builder",
-        short_name = "x64",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-# Note that the Win testers are all thin Linux VMs, triggering jobs on the
-# physical Win hardware in the Swarming pool, which is why they run on linux
-ci.dawn_builder(
-    name = "Dawn Win10 x86 Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Intel",
-        short_name = "x86",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Win10 x86 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x64 Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Intel",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Win10 x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x86 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Nvidia",
-        short_name = "x86",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Win10 x86 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x64 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|Nvidia",
-        short_name = "x64",
-    ),
-    cores = 2,
-    os = os.LINUX_DEFAULT,
-    triggered_by = ["Dawn Win10 x64 Builder"],
-)
-
-ci.dawn_builder(
-    name = "Dawn Win10 x64 ASAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT|Windows|ASAN",
-        short_name = "x64",
-    ),
-    os = os.WINDOWS_ANY,
-)
-
-ci.fuzz_builder(
-    name = "ASAN Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan",
-        short_name = "dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ASan Debug (32-bit x86 with V8-ARM)",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan|x64 v8-ARM",
-        short_name = "dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ASAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan",
-        short_name = "rel",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 5,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ASan Release (32-bit x86 with V8-ARM)",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan|x64 v8-ARM",
-        short_name = "rel",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ASAN Release Media",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan",
-        short_name = "med",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "Afl Upload Linux ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "afl",
-        short_name = "afl",
-    ),
-    executable = "recipe:chromium_afl",
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ASan Release Media (32-bit x86 with V8-ARM)",
-    console_view_entry = ci.console_view_entry(
-        category = "linux asan|x64 v8-ARM",
-        short_name = "med",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "ChromiumOS ASAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "cros asan",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 6,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "MSAN Release (chained origins)",
-    console_view_entry = ci.console_view_entry(
-        category = "linux msan",
-        short_name = "org",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "MSAN Release (no origins)",
-    console_view_entry = ci.console_view_entry(
-        category = "linux msan",
-        short_name = "rel",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "Mac ASAN Release",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "mac asan",
-        short_name = "rel",
-    ),
-    cores = 4,
-    os = os.MAC_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 2,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "Mac ASAN Release Media",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "mac asan",
-        short_name = "med",
-    ),
-    cores = 4,
-    os = os.MAC_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 2,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "TSAN Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "linux tsan",
-        short_name = "dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "TSAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "linux tsan",
-        short_name = "rel",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 3,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "UBSan Release",
-    console_view_entry = ci.console_view_entry(
-        category = "linux UBSan",
-        short_name = "rel",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "UBSan vptr Release",
-    console_view_entry = ci.console_view_entry(
-        category = "linux UBSan",
-        short_name = "vpt",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 4,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "Win ASan Release",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "win asan",
-        short_name = "rel",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 7,
-    ),
-)
-
-ci.fuzz_builder(
-    name = "Win ASan Release Media",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "win asan",
-        short_name = "med",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 6,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Chrome OS ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "chromeos-asan",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 3,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 5,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux ASan Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux-dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 5,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux MSan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux-msan",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 5,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux UBSan",
-    # Do not use builderless for this (crbug.com/980080).
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux-ubsan",
-    ),
-    execution_timeout = 3 * time.hour + 30 * time.minute,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 5,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux V8-ARM64 ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "arm64",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 1,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux V8-ARM64 ASan Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "arm64-dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 1,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux32 ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux32",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 3,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux32 ASan Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "linux32-dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 3,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux32 V8-ARM ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "arm",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 1,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Linux32 V8-ARM ASan Debug",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "arm-dbg",
-    ),
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 1,
-    ),
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Mac ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "mac-asan",
-    ),
-    cores = 24,
-    execution_timeout = 4 * time.hour,
-    os = os.MAC_DEFAULT,
-)
-
-ci.fuzz_libfuzzer_builder(
-    name = "Libfuzzer Upload Windows ASan",
-    console_view_entry = ci.console_view_entry(
-        category = "libfuzz",
-        short_name = "win-asan",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 3,
-    ),
-)
-
-ci.fyi_builder(
-    name = "Closure Compilation Linux",
-    console_view_entry = ci.console_view_entry(
-        category = "closure_compilation",
-    ),
-    executable = "recipe:closure_compilation",
-    notifies = ["Closure Compilation Linux"],
-)
-
-ci.fyi_builder(
-    name = "Linux Viz",
-    console_view_entry = ci.console_view_entry(
-        category = "viz",
-    ),
-)
-
-ci.fyi_builder(
-    name = "Linux remote_run Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "remote_run",
-    ),
-)
-
-ci.fyi_builder(
-    name = "Linux remote_run Tester",
-    console_view_entry = ci.console_view_entry(
-        category = "remote_run",
-    ),
-    triggered_by = ["Linux remote_run Builder"],
-)
-
-ci.fyi_builder(
-    name = "Mojo Android",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "and",
-    ),
-)
-
-ci.fyi_builder(
-    name = "Mojo ChromiumOS",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "cr",
-    ),
-)
-
-ci.fyi_builder(
-    name = "Mojo Linux",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "lnx",
-    ),
-)
-
-ci.fyi_builder(
-    name = "Site Isolation Android",
-    console_view_entry = ci.console_view_entry(
-        category = "site_isolation",
-    ),
-    notifies = ["Site Isolation Android"],
-)
-
-ci.fyi_builder(
-    name = "android-mojo-webview-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "aw",
-    ),
-)
-
-ci.fyi_builder(
-    name = "chromeos-amd64-generic-lacros-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "chromeos",
-    ),
-    properties = {
-        # The format of these properties is defined at archive/properties.proto
-        "$build/archive": {
-            "archive_datas": [
-                # The list of files and dirs should be synched with
-                # _TRACKED_ITEMS in //build/lacros/lacros_resource_sizes.py.
-                {
-                    "files": [
-                        "chrome",
-                        "chrome_100_percent.pak",
-                        "chrome_200_percent.pak",
-                        "crashpad_handler",
-                        "headless_lib.pak",
-                        "icudtl.dat",
-                        "nacl_helper",
-                        "nacl_irt_x86_64.nexe",
-                        "resources.pak",
-                        "snapshot_blob.bin",
-                    ],
-                    "dirs": ["locales", "swiftshader"],
-                    "gcs_bucket": "chromium-lacros-fishfood",
-                    "gcs_path": "x86_64/{%position%}/lacros.zip",
-                    "archive_type": "ARCHIVE_TYPE_ZIP",
-                },
-            ],
-        },
-    },
-)
-
-ci.fyi_builder(
-    name = "fuchsia-fyi-arm64-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|a64",
-        short_name = "dbg",
-    ),
-    notifies = ["cr-fuchsia"],
-)
-
-ci.fyi_builder(
-    name = "fuchsia-fyi-arm64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|a64",
-        short_name = "rel",
-    ),
-    notifies = ["cr-fuchsia"],
-)
-
-ci.fyi_builder(
-    name = "fuchsia-fyi-x64-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|x64",
-        short_name = "dbg",
-    ),
-    notifies = ["cr-fuchsia"],
-)
-
-ci.fyi_builder(
-    name = "fuchsia-fyi-x64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|x64",
-        short_name = "rel",
-    ),
-    notifies = ["cr-fuchsia"],
-)
-
-ci.fyi_builder(
-    name = "linux-annotator-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "network|traffic|annotations",
-        short_name = "lnx",
-    ),
-    notifies = ["annotator-rel"],
-)
-
-ci.fyi_builder(
-    name = "linux-ash-chromium-builder-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "default",
-        short_name = "lcr",
-    ),
-    properties = {
-        # The format of these properties is defined at archive/properties.proto
-        "$build/archive": {
-            "archive_datas": [
-                {
-                    "files": [
-                        "chrome",
-                        "chrome_100_percent.pak",
-                        "chrome_200_percent.pak",
-                        "crashpad_handler",
-                        "headless_lib.pak",
-                        "icudtl.dat",
-                        "libminigbm.so",
-                        "nacl_helper",
-                        "nacl_irt_x86_64.nexe",
-                        "resources.pak",
-                        "snapshot_blob.bin",
-                    ],
-                    "dirs": ["locales", "swiftshader"],
-                    "gcs_bucket": "ash-chromium-on-linux-prebuilts",
-                    "gcs_path": "x86_64/{%position%}/ash-chromium.zip",
-                    "archive_type": "ARCHIVE_TYPE_ZIP",
-                    "latest_upload": {
-                        "gcs_path": "x86_64/latest/ash-chromium.txt",
-                        "gcs_file_content": "{%position%}",
-                    },
-                },
-            ],
-        },
-    },
-)
-
-ci.fyi_builder(
-    name = "linux-blink-animation-use-time-delta",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|blink",
-        short_name = "TD",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-blink-heap-concurrent-marking-tsan-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|blink",
-        short_name = "CM",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-blink-heap-verification",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|blink",
-        short_name = "VF",
-    ),
-    notifies = ["linux-blink-heap-verification"],
-)
-
-ci.fyi_builder(
-    name = "linux-chromium-tests-staging-builder",
-    console_view_entry = ci.console_view_entry(
-        category = "recipe|staging|linux",
-        short_name = "bld",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-chromium-tests-staging-tests",
-    console_view_entry = ci.console_view_entry(
-        category = "recipe|staging|linux",
-        short_name = "tst",
-    ),
-    triggered_by = ["linux-chromium-tests-staging-builder"],
-)
-
-ci.fyi_builder(
-    name = "linux-fieldtrial-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-lacros-builder-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-lacros-tester-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-    ),
-    triggered_by = ["linux-lacros-builder-fyi-rel"],
-)
-
-ci.fyi_builder(
-    name = "linux-perfetto-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-    ),
-)
-
-ci.fyi_builder(
-    name = "linux-wpt-fyi-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-    ),
-    experimental = True,
-    goma_backend = None,
-)
-
-# This is launching & collecting entirely isolated tests.
-# OS shouldn't matter.
-ci.fyi_builder(
-    name = "mac-osxbeta-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "beta",
-    ),
-    goma_backend = None,
-    main_console_view = None,
-    triggered_by = ["ci/Mac Builder"],
-)
-
-ci.fyi_builder(
-    name = "mac-omaha-builder-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "bld",
-    ),
-    os = os.MAC_ANY,
-    cpu = cpu.X86_64,
-    builderless = True,
-    cores = None,
-)
-
-ci.fyi_builder(
-    name = "mac10.10-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.10",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "mac10.11-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.11",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "mac10.12-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.12",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "mac10.13-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.13",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "mac10.14-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.14",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "mac10.15-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|mac",
-        short_name = "10.15",
-    ),
-    triggered_by = ["mac-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "win-omaha-builder-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|win",
-        short_name = "bld",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    cpu = cpu.X86,
-)
-
-ci.fyi_builder(
-    name = "win7-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|win",
-        short_name = "7",
-    ),
-    triggered_by = ["win-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "win10-omaha-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "updater|win",
-        short_name = "10",
-    ),
-    os = os.WINDOWS_10,
-    triggered_by = ["win-omaha-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "win-pixel-builder-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "win10",
-    ),
-    os = os.WINDOWS_10,
-)
-
-ci.fyi_builder(
-    name = "win-pixel-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "win10",
-    ),
-    os = None,
-    triggered_by = ["win-pixel-builder-rel"],
-)
-
-ci.fyi_builder(
-    name = "linux-upload-perfetto",
-    console_view_entry = ci.console_view_entry(
-        category = "perfetto",
-        short_name = "lnx",
-    ),
-    os = os.LINUX_DEFAULT,
-)
-
-ci.fyi_builder(
-    name = "mac-upload-perfetto",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "perfetto",
-        short_name = "mac",
-    ),
-    os = os.MAC_DEFAULT,
-    schedule = "with 3h interval",
-    triggered_by = [],
-)
-
-ci.fyi_builder(
-    name = "win-upload-perfetto",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "perfetto",
-        short_name = "win",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    schedule = "with 3h interval",
-    triggered_by = [],
-)
-
-ci.fyi_celab_builder(
-    name = "win-celab-builder-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "celab",
-    ),
-    schedule = "0 0,6,12,18 * * *",
-    triggered_by = [],
-)
-
-ci.fyi_celab_builder(
-    name = "win-celab-tester-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "celab",
-    ),
-    triggered_by = ["win-celab-builder-rel"],
-)
-
-ci.fyi_coverage_builder(
-    name = "android-code-coverage",
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "and",
-    ),
-    use_java_coverage = True,
-    schedule = "triggered",
-    triggered_by = [],
-)
-
-ci.fyi_coverage_builder(
-    name = "android-code-coverage-native",
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "ann",
-    ),
-    use_clang_coverage = True,
-)
-
-ci.fyi_coverage_builder(
-    name = "ios-simulator-code-coverage",
-    caches = [xcode_cache.x12a8189n],
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "ios",
-    ),
-    cores = None,
-    os = os.MAC_10_15,
-    use_clang_coverage = True,
-    coverage_exclude_sources = "ios_test_files_and_test_utils",
-    coverage_test_types = ["overall", "unit"],
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_coverage_builder(
-    name = "linux-chromeos-code-coverage",
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "lcr",
-    ),
-    use_clang_coverage = True,
-    schedule = "triggered",
-    triggered_by = [],
-)
-
-ci.fyi_coverage_builder(
-    name = "linux-code-coverage",
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "lnx",
-    ),
-    use_clang_coverage = True,
-    triggered_by = [],
-)
-
-ci.fyi_coverage_builder(
-    name = "mac-code-coverage",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "mac",
-    ),
-    cores = 24,
-    os = os.MAC_ANY,
-    use_clang_coverage = True,
-)
-
-ci.fyi_coverage_builder(
-    name = "win10-code-coverage",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "code_coverage",
-        short_name = "win",
-    ),
-    os = os.WINDOWS_DEFAULT,
-    use_clang_coverage = True,
-)
-
-ci.fyi_ios_builder(
-    name = "ios-asan",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS",
-        short_name = "asan",
-    ),
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_ios_builder(
-    name = "ios-simulator-cr-recipe",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS",
-        short_name = "chr",
-    ),
-    executable = "recipe:chromium",
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_ios_builder(
-    name = "ios-simulator-multi-window",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS",
-        short_name = "mwd",
-    ),
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_ios_builder(
-    name = "ios-webkit-tot",
-    caches = [xcode_cache.x11e608cwk],
-    console_view_entry = ci.console_view_entry(
-        category = "iOS",
-        short_name = "wk",
-    ),
-    executable = "recipe:chromium",
-    properties = {
-        "xcode_build_version": "11e608cwk",
-    },
-    schedule = "0 1-23/6 * * *",
-    triggered_by = [],
-)
-
-ci.fyi_ios_builder(
-    name = "ios13-beta-simulator",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|iOS13",
-        short_name = "ios13",
-    ),
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-    schedule = "0 0,12 * * *",
-    triggered_by = [],
-)
-
-ci.fyi_ios_builder(
-    name = "ios13-sdk-device",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|iOS13",
-        short_name = "dev",
-    ),
-    caches = [xcode_cache.x12a8189n],
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_ios_builder(
-    name = "ios13-sdk-simulator",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|iOS13",
-        short_name = "sdk13",
-    ),
-    caches = [xcode_cache.x12a8189n],
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-    schedule = "0 6,18 * * *",
-    triggered_by = [],
-)
-
-ci.fyi_ios_builder(
-    name = "ios14-beta-simulator",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|iOS14",
-        short_name = "ios14",
-    ),
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_ios_builder(
-    name = "ios14-sdk-simulator",
-    console_view_entry = ci.console_view_entry(
-        category = "iOS|iOS14",
-        short_name = "sdk14",
-    ),
-    caches = [xcode_cache.x12a8189n],
-    executable = "recipe:chromium",
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.fyi_mac_builder(
-    name = "Mac Builder Next",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "bld",
-    ),
-    cores = None,
-    os = None,
-)
-
-ci.thin_tester(
-    name = "Mac11.0 Tests",
-    mastername = "chromium.fyi",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "11.0",
-    ),
-    triggered_by = ["Mac Builder Next"],
-)
-
-ci.fyi_mac_builder(
-    name = "Mac deterministic",
-    console_view_entry = ci.console_view_entry(
-        category = "deterministic|mac",
-        short_name = "rel",
-    ),
-    cores = None,
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-)
-
-ci.fyi_mac_builder(
-    name = "Mac deterministic (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "deterministic|mac",
-        short_name = "dbg",
-    ),
-    cores = None,
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-)
-
-ci.fyi_mac_builder(
-    name = "mac-hermetic-upgrade-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "herm",
-    ),
-    cores = 8,
-)
-
-ci.fyi_mac_builder(
-    name = "mac-mojo-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "mac",
-    ),
-    os = os.MAC_ANY,
-)
-
-ci.fyi_windows_builder(
-    name = "Win10 Tests x64 1803",
-    console_view_entry = ci.console_view_entry(
-        category = "win10|1803",
-    ),
-    goma_backend = None,
-    main_console_view = None,
-    os = os.WINDOWS_10,
-    triggered_by = ["ci/Win x64 Builder"],
-)
-
-ci.fyi_windows_builder(
-    name = "Win10 Tests x64 1909",
-    console_view_entry = ci.console_view_entry(
-        category = "win10|1909",
-    ),
-    goma_backend = None,
-    main_console_view = None,
-    os = os.WINDOWS_10,
-    triggered_by = ["ci/Win x64 Builder"],
-)
-
-ci.fyi_windows_builder(
-    name = "Win 10 Fast Ring",
-    console_view_entry = ci.console_view_entry(
-        category = "win10",
-    ),
-    os = os.WINDOWS_10,
-    notifies = ["Win 10 Fast Ring"],
-)
-
-ci.fyi_windows_builder(
-    name = "win32-arm64-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "win32|arm64",
-    ),
-    cpu = cpu.X86,
-    goma_jobs = goma.jobs.J150,
-)
-
-ci.fyi_windows_builder(
-    name = "win-annotator-rel",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "network|traffic|annotations",
-        short_name = "win",
-    ),
-    execution_timeout = 16 * time.hour,
-    notifies = ["annotator-rel"],
-)
-
-ci.fyi_windows_builder(
-    name = "Mojo Windows",
-    console_view_entry = ci.console_view_entry(
-        category = "mojo",
-        short_name = "win",
-    ),
-)
-
-ci.gpu_builder(
-    name = "GPU Linux Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux",
-    ),
-    tree_closing = False,
-)
-
-ci.gpu_builder(
-    name = "GPU Mac Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac",
-    ),
-    cores = None,
-    os = os.MAC_ANY,
-    tree_closing = False,
-)
-
-ci.gpu_builder(
-    name = "GPU Win x64 Builder (dbg)",
-    builderless = True,
-    console_view_entry = ci.console_view_entry(
-        category = "Windows",
-    ),
-    os = os.WINDOWS_ANY,
-    tree_closing = False,
-)
-
-ci.gpu_thin_tester(
-    name = "Linux Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux",
-    ),
-    triggered_by = ["GPU Linux Builder (dbg)"],
-    tree_closing = False,
-)
-
-ci.gpu_thin_tester(
-    name = "Mac Debug (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac",
-    ),
-    triggered_by = ["GPU Mac Builder (dbg)"],
-    tree_closing = False,
-)
-
-ci.gpu_thin_tester(
-    name = "Mac Retina Debug (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac",
-    ),
-    triggered_by = ["GPU Mac Builder (dbg)"],
-    tree_closing = False,
-)
-
-ci.gpu_thin_tester(
-    name = "Win10 x64 Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows",
-    ),
-    triggered_by = ["GPU Win x64 Builder (dbg)"],
-    tree_closing = False,
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI 32 Vk Release (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|vk|Q32",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI 32 dEQP Vk Release (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|dqp|vk|Q32",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI 64 Perf (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|Perf|Q64",
-        short_name = "P2",
-    ),
-    cores = 2,
-    triggered_by = ["GPU FYI Perf Android 64 Builder"],
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI 64 Vk Release (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|vk|Q64",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI 64 dEQP Vk Release (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|dqp|vk|Q64",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (NVIDIA Shield TV)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|N64|NVDA",
-        short_name = "STV",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Nexus 5)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|L32",
-        short_name = "N5",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Nexus 5X)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|M64|QCOM",
-        short_name = "N5X",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Nexus 6)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|L32",
-        short_name = "N6",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Nexus 6P)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|M64|QCOM",
-        short_name = "N6P",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Nexus 9)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|M64|NVDA",
-        short_name = "N9",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI Release (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|P32|QCOM",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI SkiaRenderer GL (Nexus 5X)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|skgl|M64",
-        short_name = "N5X",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI SkiaRenderer Vulkan (Pixel 2)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|skv|P32",
-        short_name = "P2",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Android FYI dEQP Release (Nexus 5X)",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|dqp|M64",
-        short_name = "N5X",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "ChromeOS FYI Release (amd64-generic)",
-    console_view_entry = ci.console_view_entry(
-        category = "ChromeOS|amd64|generic",
-        short_name = "x64",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "ChromeOS FYI Release (kevin)",
-    console_view_entry = ci.console_view_entry(
-        category = "ChromeOS|arm|kevin",
-        short_name = "kvn",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "GPU FYI Linux Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Builder",
-        short_name = "rel",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "GPU FYI Linux Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Builder",
-        short_name = "dbg",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "GPU FYI Linux Ozone Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Builder",
-        short_name = "ozn",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "GPU FYI Linux dEQP Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Builder",
-        short_name = "dqp",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "GPU FYI Perf Android 64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Android|Perf|Builder",
-        short_name = "64",
-    ),
-)
-
-ci.gpu_fyi_linux_builder(
-    name = "Linux FYI GPU TSAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux",
-        short_name = "tsn",
-    ),
-)
-
-# Builder + tester.
-ci.gpu_fyi_linux_builder(
-    name = "Linux FYI SkiaRenderer Dawn Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "skd",
-    ),
-)
-
-ci.gpu_fyi_mac_builder(
-    name = "Mac FYI arm64 Release (Apple DTK)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac",
-        short_name = "dtk",
-    ),
-    cores = 8,
-)
-
-ci.gpu_fyi_mac_builder(
-    name = "Mac FYI GPU ASAN Release",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac",
-        short_name = "asn",
-    ),
-)
-
-ci.gpu_fyi_mac_builder(
-    name = "GPU FYI Mac Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Builder",
-        short_name = "rel",
-    ),
-)
-
-ci.gpu_fyi_mac_builder(
-    name = "GPU FYI Mac Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Builder",
-        short_name = "dbg",
-    ),
-)
-
-ci.gpu_fyi_mac_builder(
-    name = "GPU FYI Mac dEQP Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Builder",
-        short_name = "dqp",
-    ),
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Nvidia",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Linux Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Experimental Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Experimental Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Nvidia",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Ozone (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "ozn",
-    ),
-    triggered_by = ["GPU FYI Linux Ozone Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Release (AMD R7 240)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|AMD",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI Release (Intel UHD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "uhd",
-    ),
-    # TODO(https://crbug.com/986939): Remove this increased timeout once more
-    # devices are added.
-    execution_timeout = 18 * time.hour,
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI SkiaRenderer Vulkan (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "skv",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI SkiaRenderer Vulkan (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Nvidia",
-        short_name = "skv",
-    ),
-    triggered_by = ["GPU FYI Linux Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI dEQP Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Intel",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Linux dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Linux FYI dEQP Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Linux|Nvidia",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Linux dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Debug (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Intel",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Mac Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Experimental Release (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Intel",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Experimental Retina Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|AMD|Retina",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Experimental Retina Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Nvidia",
-        short_name = "exp",
-    ),
-    # This bot has one machine backing its tests at the moment.
-    # If it gets more, this can be removed.
-    # See crbug.com/853307 for more context.
-    execution_timeout = 12 * time.hour,
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Release (Intel)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Intel",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Retina Debug (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|AMD|Retina",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Mac Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Retina Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Nvidia",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Mac Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Retina Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|AMD|Retina",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI Retina Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI dEQP Release AMD",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|AMD",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Mac dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac FYI dEQP Release Intel",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|Intel",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Mac dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Mac Pro FYI Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Mac|AMD|Pro",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Mac Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 DX12 Vulkan Debug (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia|dx12vk",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Win x64 DX12 Vulkan Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 DX12 Vulkan Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia|dx12vk",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win x64 DX12 Vulkan Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Exp Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Intel",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Exp Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "exp",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release (AMD RX 550)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|AMD",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Intel",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release (Intel UHD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Intel",
-        short_name = "uhd",
-    ),
-    # TODO(https://crbug.com/986939): Remove this increased timeout once
-    # more devices are added.
-    execution_timeout = 18 * time.hour,
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release (NVIDIA GeForce GTX 1660)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "gtx",
-    ),
-    execution_timeout = 18 * time.hour,
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 Release XR Perf (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "xr",
-    ),
-    triggered_by = ["GPU FYI XR Win x64 Builder"],
-)
-
-# Builder + tester.
-ci.gpu_fyi_windows_builder(
-    name = "Win10 FYI x64 SkiaRenderer Dawn Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "skd",
-    ),
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 SkiaRenderer GL (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "skgl",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 dEQP Release (Intel HD 630)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Intel",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x64 dEQP Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x64|Nvidia",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win10 FYI x86 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|10|x86|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI Debug (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x86|AMD",
-        short_name = "dbg",
-    ),
-    triggered_by = ["GPU FYI Win Builder (dbg)"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x86|AMD",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x86|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI dEQP Release (AMD)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x86|AMD",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Win dEQP Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI x64 Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x64|Nvidia",
-        short_name = "rel",
-    ),
-    triggered_by = ["GPU FYI Win x64 Builder"],
-)
-
-ci.gpu_fyi_thin_tester(
-    name = "Win7 FYI x64 dEQP Release (NVIDIA)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|7|x64|Nvidia",
-        short_name = "dqp",
-    ),
-    triggered_by = ["GPU FYI Win x64 dEQP Builder"],
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|Release",
-        short_name = "x86",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|Debug",
-        short_name = "x86",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win dEQP Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|dEQP",
-        short_name = "x86",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win x64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|Release",
-        short_name = "x64",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win x64 Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|Debug",
-        short_name = "x64",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win x64 dEQP Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|dEQP",
-        short_name = "x64",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win x64 DX12 Vulkan Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|dx12vk",
-        short_name = "rel",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI Win x64 DX12 Vulkan Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|dx12vk",
-        short_name = "dbg",
-    ),
-)
-
-ci.gpu_fyi_windows_builder(
-    name = "GPU FYI XR Win x64 Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "Windows|Builder|XR",
-        short_name = "x64",
-    ),
-)
-
-ci.linux_builder(
-    name = "Cast Audio Linux",
-    console_view_entry = ci.console_view_entry(
-        category = "cast",
-        short_name = "aud",
-    ),
-    main_console_view = "main",
-    ssd = True,
-)
-
-ci.linux_builder(
-    name = "Deterministic Fuchsia (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|x64",
-        short_name = "det",
-    ),
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    goma_jobs = None,
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "Deterministic Linux",
-    console_view_entry = ci.console_view_entry(
-        category = "release",
-        short_name = "det",
-    ),
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    main_console_view = "main",
-    # Set tree_closing to false to disable the defaualt tree closer, which
-    # filters by step name, and instead enable tree closing for any step
-    # failure.
-    tree_closing = False,
-    extra_notifies = ["Deterministic Linux", "close-on-any-step-failure"],
-)
-
-ci.linux_builder(
-    name = "Deterministic Linux (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "debug|builder",
-        short_name = "det",
-    ),
-    cores = 32,
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "Leak Detection Linux",
-    console_view = "chromium.fyi",
-    console_view_entry = ci.console_view_entry(
-        category = "linux",
-        short_name = "lk",
-    ),
-    notifies = [],
-    tree_closing = False,
-)
-
-ci.linux_builder(
-    name = "Linux Builder (dbg)(32)",
-    console_view_entry = ci.console_view_entry(
-        category = "debug|builder",
-        short_name = "32",
-    ),
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "Network Service Linux",
-    console_view_entry = ci.console_view_entry(
-        category = "release",
-        short_name = "nsl",
-    ),
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "fuchsia-x64-dbg",
-    console_view_entry = ci.console_view_entry(
-        category = "fuchsia|x64",
-        short_name = "dbg",
-    ),
-    main_console_view = "main",
-    extra_notifies = ["cr-fuchsia"],
-)
-
-ci.linux_builder(
-    name = "linux-bfcache-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "bfcache",
-        short_name = "bfc",
-    ),
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "linux-gcc-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "release",
-        short_name = "gcc",
-    ),
-    goma_backend = None,
-    main_console_view = "main",
-)
-
-ci.linux_builder(
-    name = "linux-trusty-rel",
-    console_view_entry = ci.console_view_entry(
-        category = "release",
-        short_name = "tru",
-    ),
-    main_console_view = "main",
-    os = os.LINUX_TRUSTY,
-)
-
-ci.linux_builder(
-    name = "metadata-exporter",
-    executable = "recipe:chromium_export_metadata",
-    service_account = "component-mapping-updater@chops-service-accounts.iam.gserviceaccount.com",
-    notifies = ["metadata-mapping"],
-    tree_closing = False,
-)
-
-ci.mac_ios_builder(
-    name = "ios-device",
-    console_view_entry = ci.console_view_entry(
-        category = "ios|default",
-        short_name = "dev",
-    ),
-    # We don't have necessary capacity to run this configuration in CQ, but it
-    # is part of the main waterfall
-    main_console_view = "main",
-)
-
-ci.mac_ios_builder(
-    name = "ios-simulator-noncq",
-    caches = [
-        xcode_cache.x12a8189n,
-    ],
-    console_view_entry = ci.console_view_entry(
-        category = "ios|default",
-        short_name = "non",
-    ),
-    # We don't have necessary capacity to run this configuration in CQ, but it
-    # is part of the main waterfall
-    main_console_view = "main",
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-ci.memory_builder(
-    name = "Android CFI",
-    # TODO(https://crbug.com/1008094) When this builder is not consistently
-    # failing, remove the console_view value
-    console_view = "chromium.android.fyi",
-    console_view_entry = ci.console_view_entry(
-        category = "memory",
-        short_name = "cfi",
-    ),
-    cores = 32,
-    # TODO(https://crbug.com/919430) Remove the larger timeout once compile
-    # times have been brought down to reasonable level
-    execution_timeout = 4 * time.hour + 30 * time.minute,
-    tree_closing = False,
-)
-
-ci.memory_builder(
-    name = "Linux CFI",
-    console_view_entry = ci.console_view_entry(
-        category = "cfi",
-        short_name = "lnx",
-    ),
-    cores = 32,
-    # TODO(thakis): Remove once https://crbug.com/927738 is resolved.
-    execution_timeout = 4 * time.hour,
-    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux Chromium OS ASan LSan Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "cros|asan",
-        short_name = "bld",
-    ),
-    # TODO(crbug.com/1030593): Builds take more than 3 hours sometimes. Remove
-    # once the builds are faster.
-    execution_timeout = 6 * time.hour,
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux Chromium OS ASan LSan Tests (1)",
-    console_view_entry = ci.console_view_entry(
-        category = "cros|asan",
-        short_name = "tst",
-    ),
-    triggered_by = ["Linux Chromium OS ASan LSan Builder"],
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux ChromiumOS MSan Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "cros|msan",
-        short_name = "bld",
-    ),
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux ChromiumOS MSan Tests",
-    console_view_entry = ci.console_view_entry(
-        category = "cros|msan",
-        short_name = "tst",
-    ),
-    triggered_by = ["Linux ChromiumOS MSan Builder"],
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux MSan Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|msan",
-        short_name = "bld",
-    ),
-    goma_jobs = goma.jobs.MANY_JOBS_FOR_CI,
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Linux MSan Tests",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|msan",
-        short_name = "tst",
-    ),
-    triggered_by = ["Linux MSan Builder"],
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "Mac ASan 64 Builder",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "bld",
-    ),
-    goma_debug = True,  # TODO(hinoka): Remove this after debugging.
-    goma_jobs = None,
-    cores = None,  # Swapping between 8 and 24
-    main_console_view = "main",
-    os = os.MAC_DEFAULT,
-    triggering_policy = scheduler.greedy_batching(
-        max_concurrent_invocations = 2,
-    ),
-)
-
-ci.memory_builder(
-    name = "Mac ASan 64 Tests (1)",
-    builderless = False,
-    console_view_entry = ci.console_view_entry(
-        category = "mac",
-        short_name = "tst",
-    ),
-    main_console_view = "main",
-    os = os.MAC_DEFAULT,
-    triggered_by = ["Mac ASan 64 Builder"],
-)
-
-ci.memory_builder(
-    name = "WebKit Linux ASAN",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|webkit",
-        short_name = "asn",
-    ),
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "WebKit Linux Leak",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|webkit",
-        short_name = "lk",
-    ),
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "WebKit Linux MSAN",
-    console_view_entry = ci.console_view_entry(
-        category = "linux|webkit",
-        short_name = "msn",
-    ),
-    main_console_view = "main",
-)
-
-ci.memory_builder(
-    name = "android-asan",
-    console_view_entry = ci.console_view_entry(
-        category = "android",
-        short_name = "asn",
-    ),
-    main_console_view = "main",
-    tree_closing = False,
-)
-
-ci.memory_builder(
-    name = "win-asan",
-    console_view_entry = ci.console_view_entry(
-        category = "win",
-        short_name = "asn",
-    ),
-    cores = 32,
-    builderless = True,
-    main_console_view = "main",
-    os = os.WINDOWS_DEFAULT,
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-chromium-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "Chromium|Linux",
-        short_name = "x64",
-    ),
-    pinned = False,
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-tot-angle-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT ANGLE|Linux",
-        short_name = "x64",
-    ),
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-tot-angle-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT ANGLE|Linux",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-tot-swiftshader-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT SwiftShader|Linux",
-        short_name = "x64",
-    ),
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-tot-swiftshader-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT SwiftShader|Linux",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "DEPS|Linux",
-        short_name = "x64",
-    ),
-    pinned = False,
-)
-
-ci.swangle_linux_builder(
-    name = "linux-swangle-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "DEPS|Linux",
-        short_name = "x86",
-    ),
-    pinned = False,
-)
-
-ci.swangle_mac_builder(
-    name = "mac-swangle-chromium-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "Chromium|Mac",
-        short_name = "x64",
-    ),
-    pinned = False,
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-chromium-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "Chromium|Windows",
-        short_name = "x86",
-    ),
-    pinned = False,
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-tot-angle-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT ANGLE|Windows",
-        short_name = "x64",
-    ),
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-tot-angle-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT ANGLE|Windows",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-tot-swiftshader-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT SwiftShader|Windows",
-        short_name = "x64",
-    ),
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-tot-swiftshader-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "ToT SwiftShader|Windows",
-        short_name = "x86",
-    ),
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-x64",
-    console_view_entry = ci.console_view_entry(
-        category = "DEPS|Windows",
-        short_name = "x64",
-    ),
-    pinned = False,
-)
-
-ci.swangle_windows_builder(
-    name = "win-swangle-x86",
-    console_view_entry = ci.console_view_entry(
-        category = "DEPS|Windows",
-        short_name = "x86",
-    ),
-    pinned = False,
-)
-
-ci.win_builder(
-    name = "WebKit Win10",
-    console_view_entry = ci.console_view_entry(
-        category = "misc",
-        short_name = "wbk",
-    ),
-    main_console_view = "main",
-    triggered_by = ["Win Builder"],
-)
-
-ci.win_builder(
-    name = "Win Builder",
-    console_view_entry = ci.console_view_entry(
-        category = "release|builder",
-        short_name = "32",
-    ),
-    cores = 32,
-    main_console_view = "main",
-    os = os.WINDOWS_ANY,
-)
-
-ci.win_builder(
-    name = "Win x64 Builder (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "debug|builder",
-        short_name = "64",
-    ),
-    cores = 32,
-    builderless = True,
-    main_console_view = "main",
-    os = os.WINDOWS_ANY,
-)
-
-ci.win_builder(
-    name = "Win10 Tests x64 (dbg)",
-    console_view_entry = ci.console_view_entry(
-        category = "debug|tester",
-        short_name = "10",
-    ),
-    main_console_view = "main",
-    triggered_by = ["Win x64 Builder (dbg)"],
-    # Too flaky. See crbug.com/876224 for more details.
-    tree_closing = False,
-)
-
-ci.win_builder(
-    name = "Win7 (32) Tests",
-    console_view_entry = ci.console_view_entry(
-        category = "release|tester",
-        short_name = "32",
-    ),
-    main_console_view = "main",
-    os = os.WINDOWS_7,
-    triggered_by = ["Win Builder"],
-)
-
-ci.win_builder(
-    name = "Win7 Tests (1)",
-    console_view_entry = ci.console_view_entry(
-        category = "release|tester",
-        short_name = "32",
-    ),
-    main_console_view = "main",
-    os = os.WINDOWS_7,
-    triggered_by = ["Win Builder"],
-)
-
-ci.win_builder(
-    name = "Windows deterministic",
-    console_view_entry = ci.console_view_entry(
-        category = "misc",
-        short_name = "det",
-    ),
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-    goma_jobs = goma.jobs.J150,
-    main_console_view = "main",
-)
diff --git a/infra/config/subprojects/chromium/master-only/master-only.star b/infra/config/subprojects/chromium/master-only/master-only.star
deleted file mode 100644
index 1330a9d..0000000
--- a/infra/config/subprojects/chromium/master-only/master-only.star
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# TODO(gbeaty) external_console_view uses new fields/types that aren't present
-# in the version of the protobuf that lint-luci-milo uses, so update protos and
-# then uncomment these (the main console is still reachable via the beta link in
-# the header)
-# luci.external_console_view(
-#     name = "main-m86",
-#     title = "Chromium M86 Main Console",
-#     source = "chromium-m86:main",
-# )
-
-# luci.external_console_view(
-#     name = "mirrors-m86",
-#     title = "Chromium M86 CQ Mirrors Console",
-#     source = "chromium-m86:mirrors",
-# )
-
-# luci.external_console_view(
-#     name = "try-m86",
-#     title = "Chromium M86 CQ Console",
-#     source = "chromium-m86:try",
-# )
-
-exec("./ci.star")
-exec("./gpu.try.star")
-exec("./swangle.try.star")
-exec("./try.star")
-
-exec("./consoles/android.packager.star")
-exec("./consoles/luci.chromium.try.star")
-exec("./consoles/metadata.exporter.star")
-exec("./consoles/sheriff.ios.star")
-
-exec("./fallback-cq.star")
diff --git a/infra/config/subprojects/chromium/master-only/try.star b/infra/config/subprojects/chromium/master-only/try.star
deleted file mode 100644
index 9ac49b69..0000000
--- a/infra/config/subprojects/chromium/master-only/try.star
+++ /dev/null
@@ -1,790 +0,0 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-load("//lib/builders.star", "goma", "os", "xcode_cache")
-load("//lib/try.star", "try_")
-load("//project.star", "settings")
-
-# Execute the versioned files to define all of the per-branch entities
-# (bucket, builders, console, cq_group, etc.)
-exec("../versioned/m85/buckets/try.star")
-
-try_.set_defaults(
-    settings,
-    add_to_list_view = True,
-)
-
-# *** After this point everything is trunk only ***
-
-# Builders are sorted first lexicographically by the function used to define
-# them, then lexicographically by their name
-
-try_.blink_builder(
-    name = "linux-blink-optional-highdpi-rel",
-    goma_backend = goma.backend.RBE_PROD,
-)
-
-try_.blink_builder(
-    name = "win10-blink-rel",
-    goma_backend = goma.backend.RBE_PROD,
-    os = os.WINDOWS_ANY,
-    builderless = True,
-)
-
-try_.blink_builder(
-    name = "win7-blink-rel",
-    goma_backend = goma.backend.RBE_PROD,
-    os = os.WINDOWS_ANY,
-    builderless = True,
-)
-
-try_.blink_mac_builder(
-    name = "mac10.12-blink-rel",
-)
-
-try_.blink_mac_builder(
-    name = "mac10.13-blink-rel",
-)
-
-try_.blink_mac_builder(
-    name = "mac10.14-blink-rel",
-)
-
-try_.blink_mac_builder(
-    name = "mac10.15-blink-rel",
-)
-
-try_.blink_mac_builder(
-    name = "mac11.0-blink-rel",
-    builderless = False,
-)
-
-try_.chromium_android_builder(
-    name = "android-asan",
-)
-
-try_.chromium_android_builder(
-    name = "android-bfcache-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-cronet-marshmallow-arm64-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-deterministic-dbg",
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-)
-
-try_.chromium_android_builder(
-    name = "android-deterministic-rel",
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-)
-
-try_.chromium_android_builder(
-    name = "android-marshmallow-x86-fyi-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-opus-arm-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-oreo-arm64-cts-networkservice-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-oreo-arm64-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-pie-x86-rel",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_android_builder(
-    name = "android-pie-arm64-coverage-rel",
-    cores = 16,
-    goma_jobs = goma.jobs.J300,
-    ssd = True,
-    use_clang_coverage = True,
-)
-
-try_.chromium_android_builder(
-    name = "android-10-arm64-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-weblayer-pie-arm64-fyi-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-weblayer-pie-x86-fyi-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android-webview-marshmallow-arm64-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-webview-nougat-arm64-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-webview-oreo-arm64-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-webview-pie-arm64-dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android-webview-pie-arm64-fyi-rel",
-)
-
-try_.chromium_android_builder(
-    name = "android_archive_rel_ng",
-)
-
-try_.chromium_android_builder(
-    name = "android_arm64_dbg_recipe",
-    goma_jobs = goma.jobs.J300,
-)
-
-try_.chromium_android_builder(
-    name = "android_blink_rel",
-)
-
-try_.chromium_android_builder(
-    name = "android_cfi_rel_ng",
-    cores = 32,
-)
-
-try_.chromium_android_builder(
-    name = "android_clang_dbg_recipe",
-    goma_jobs = goma.jobs.J300,
-)
-
-try_.chromium_android_builder(
-    name = "android_mojo",
-)
-
-try_.chromium_android_builder(
-    name = "android_n5x_swarming_dbg",
-)
-
-try_.chromium_android_builder(
-    name = "android_unswarmed_pixel_aosp",
-)
-
-try_.chromium_android_builder(
-    name = "linux_android_dbg_ng",
-)
-
-try_.chromium_android_builder(
-    name = "try-nougat-phone-tester",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_deqp_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_vk32_deqp_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_vk32_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_vk64_deqp_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "android_angle_vk64_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "fuchsia-angle-rel",
-)
-
-try_.chromium_angle_builder(
-    name = "linux-angle-rel",
-)
-
-try_.chromium_angle_builder(
-    name = "linux_angle_deqp_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "linux_angle_ozone_rel_ng",
-)
-
-try_.chromium_angle_builder(
-    name = "mac-angle-rel",
-    cores = None,
-    os = os.MAC_ANY,
-)
-
-try_.chromium_angle_builder(
-    name = "win-angle-deqp-rel-32",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_angle_builder(
-    name = "win-angle-deqp-rel-64",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_angle_builder(
-    name = "win-angle-rel-32",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_angle_builder(
-    name = "win-angle-rel-64",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_chromiumos_builder(
-    name = "chromeos-amd64-generic-cfi-thin-lto-rel",
-)
-
-try_.chromium_chromiumos_builder(
-    name = "chromeos-arm-generic-dbg",
-)
-
-try_.chromium_chromiumos_builder(
-    name = "chromeos-kevin-compile-rel",
-)
-
-try_.chromium_chromiumos_builder(
-    name = "chromeos-kevin-rel",
-    main_list_view = "try",
-    tryjob = try_.job(
-        location_regexp = [
-            ".+/[+]/build/chromeos/.+",
-            ".+/[+]/build/config/chromeos/.*",
-            ".+/[+]/chromeos/CHROMEOS_LKGM",
-        ],
-    ),
-)
-
-try_.chromium_chromiumos_builder(
-    name = "linux-lacros-rel",
-    main_list_view = "try",
-    tryjob = try_.job(),
-)
-
-try_.chromium_chromiumos_builder(
-    name = "linux-chromeos-dbg",
-)
-
-try_.chromium_dawn_builder(
-    name = "linux-dawn-rel",
-)
-
-try_.chromium_dawn_builder(
-    name = "mac-dawn-rel",
-    os = os.MAC_ANY,
-)
-
-try_.chromium_dawn_builder(
-    name = "win-dawn-rel",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_dawn_builder(
-    name = "dawn-try-win10-x86-rel",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_dawn_builder(
-    name = "dawn-try-win10-x64-asan-rel",
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_linux_builder(
-    name = "cast_shell_audio_linux",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-lacros-fyi-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "fuchsia-compile-x64-dbg",
-    tryjob = try_.job(
-        experiment_percentage = 50,
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = "fuchsia-fyi-arm64-dbg",
-)
-
-try_.chromium_linux_builder(
-    name = "fuchsia-fyi-arm64-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "fuchsia-fyi-x64-dbg",
-)
-
-try_.chromium_linux_builder(
-    name = "fuchsia-fyi-x64-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "layout_test_leak_detection",
-)
-
-try_.chromium_linux_builder(
-    name = "leak_detection_linux",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-annotator-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-bfcache-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-blink-heap-concurrent-marking-tsan-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-blink-heap-verification-try",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-clang-tidy-dbg",
-    executable = "recipe:tricium_clang_tidy_wrapper",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_linux_builder(
-    name = "linux-clang-tidy-rel",
-    executable = "recipe:tricium_clang_tidy_wrapper",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_linux_builder(
-    name = "linux-dcheck-off-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-gcc-rel",
-    goma_backend = None,
-)
-
-try_.chromium_linux_builder(
-    name = "linux-perfetto-rel",
-    tryjob = try_.job(
-        experiment_percentage = 100,
-        location_regexp = [
-            ".+/[+]/base/trace_event/.+",
-            ".+/[+]/base/tracing/.+",
-            ".+/[+]/components/tracing/.+",
-            ".+/[+]/content/browser/tracing/.+",
-            ".+/[+]/services/tracing/.+",
-        ],
-    ),
-)
-
-try_.chromium_linux_builder(
-    name = "linux-trusty-rel",
-    goma_jobs = goma.jobs.J150,
-    os = os.LINUX_TRUSTY,
-)
-
-try_.chromium_linux_builder(
-    name = "linux-viz-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-webkit-msan-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_analysis",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_archive_rel_ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_cfi_rel_ng",
-    cores = 32,
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_chromeos_asan_rel_ng",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_chromeos_msan_rel_ng",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_clobber_deterministic",
-    executable = "recipe:swarming/deterministic_build",
-    execution_timeout = 6 * time.hour,
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_clobber_rel_ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_compile_dbg_32_ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_compile_rel_ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_msan_rel_ng",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_linux_builder(
-    name = "linux_chromium_ubsan_rel_ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-layout-tests-edit-ng",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-autofill-assistant",
-)
-
-try_.chromium_linux_builder(
-    name = "linux-layout-tests-fragment-item",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_mojo",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_mojo_chromeos",
-)
-
-try_.chromium_linux_builder(
-    name = "linux_upload_clang",
-    builderless = True,
-    cores = 32,
-    executable = "recipe:chromium_upload_clang",
-    goma_backend = None,
-    os = os.LINUX_TRUSTY,
-)
-
-try_.chromium_linux_builder(
-    name = "linux-wpt-fyi-rel",
-)
-
-try_.chromium_linux_builder(
-    name = "network_service_linux",
-)
-
-try_.chromium_linux_builder(
-    name = "tricium-metrics-analysis",
-    executable = "recipe:tricium_metrics",
-)
-
-try_.chromium_mac_builder(
-    name = "mac-coverage-rel",
-    use_clang_coverage = True,
-    goma_jobs = goma.jobs.J150,
-    tryjob = try_.job(experiment_percentage = 5),
-)
-
-try_.chromium_mac_builder(
-    name = "mac-osxbeta-rel",
-    os = os.MAC_DEFAULT,
-)
-
-# NOTE: the following trybots aren't sensitive to Mac version on which
-# they are built, hence no additional dimension is specified.
-# The 10.xx version translates to which bots will run isolated tests.
-try_.chromium_mac_builder(
-    name = "mac_chromium_10.10",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_10.12_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_10.13_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_10.14_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_10.15_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_11.0_rel_ng",
-    builderless = False,
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_archive_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_asan_rel_ng",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_compile_rel_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_chromium_dbg_ng",
-)
-
-try_.chromium_mac_builder(
-    name = "mac_upload_clang",
-    builderless = False,
-    caches = [
-        swarming.cache(
-            name = "xcode_mac_9a235",
-            path = "xcode_mac_9a235.app",
-        ),
-    ],
-    executable = "recipe:chromium_upload_clang",
-    execution_timeout = 6 * time.hour,
-    goma_backend = None,  # Does not use Goma.
-    properties = {
-        "$depot_tools/osx_sdk": {
-            "sdk_version": "9a235",
-        },
-    },
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-device",
-    executable = "recipe:chromium_trybot",
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-simulator-code-coverage",
-    executable = "recipe:chromium_trybot",
-    use_clang_coverage = True,
-    coverage_exclude_sources = "ios_test_files_and_test_utils",
-    coverage_test_types = ["unit"],
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-    tryjob = try_.job(experiment_percentage = 3),
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-simulator-cr-recipe",
-    executable = "recipe:chromium_trybot",
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-simulator-eg",
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-simulator-multi-window",
-    executable = "recipe:chromium_trybot",
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios-simulator-noncq",
-    executable = "recipe:chromium_trybot",
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios13-beta-simulator",
-    executable = "recipe:chromium_trybot",
-    caches = [xcode_cache.x12a8189n],
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios13-sdk-simulator",
-    executable = "recipe:chromium_trybot",
-    caches = [xcode_cache.x12a8189n],
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios14-beta-simulator",
-    executable = "recipe:chromium_trybot",
-    caches = [xcode_cache.x12a8189n],
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-try_.chromium_mac_ios_builder(
-    name = "ios14-sdk-simulator",
-    executable = "recipe:chromium_trybot",
-    caches = [xcode_cache.x12a8189n],
-    os = os.MAC_10_15,
-    properties = {
-        "xcode_build_version": "12a8189n",
-    },
-)
-
-try_.chromium_win_builder(
-    name = "win-annotator-rel",
-)
-
-try_.chromium_win_builder(
-    name = "win-asan",
-    goma_jobs = goma.jobs.J150,
-)
-
-try_.chromium_win_builder(
-    name = "win-celab-try-rel",
-    executable = "recipe:celab",
-    properties = {
-        "exclude": "chrome_only",
-        "pool_name": "celab-chromium-try",
-        "pool_size": 20,
-        "tests": "*",
-    },
-)
-
-try_.chromium_win_builder(
-    name = "win10_chromium_x64_dbg_ng",
-    os = os.WINDOWS_10,
-)
-
-try_.chromium_win_builder(
-    name = "win10_chromium_x64_rel_ng_exp",
-    builderless = False,
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_win_builder(
-    name = "win_archive",
-)
-
-try_.chromium_win_builder(
-    name = "win_chromium_compile_rel_ng",
-)
-
-try_.chromium_win_builder(
-    name = "win_chromium_dbg_ng",
-)
-
-try_.chromium_win_builder(
-    name = "win_chromium_x64_rel_ng",
-)
-
-try_.chromium_win_builder(
-    name = "win_mojo",
-)
-
-try_.chromium_win_builder(
-    name = "win_upload_clang",
-    builderless = False,
-    cores = 32,
-    executable = "recipe:chromium_upload_clang",
-    goma_backend = None,
-    os = os.WINDOWS_ANY,
-)
-
-try_.chromium_win_builder(
-    name = "win_x64_archive",
-)
-
-# Used for listing chrome trybots in chromium's commit-queue.cfg without also
-# adding them to chromium's cr-buildbucket.cfg. Note that the recipe these
-# builders run allow only known roller accounts when triggered via the CQ.
-def chrome_internal_verifier(
-        *,
-        builder):
-    luci.cq_tryjob_verifier(
-        builder = "chrome:try/" + builder,
-        cq_group = "cq",
-        includable_only = True,
-        owner_whitelist = [
-            "googlers",
-            "project-chromium-robot-committers",
-        ],
-    )
-
-chrome_internal_verifier(
-    builder = "chromeos-betty-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "chromeos-betty-pi-arc-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "chromeos-eve-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "chromeos-eve-compile-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "chromeos-kevin-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "chromeos-kevin-compile-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "ipad-device",
-)
-
-chrome_internal_verifier(
-    builder = "iphone-device",
-)
-
-chrome_internal_verifier(
-    builder = "linux-chromeos-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "mac-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "win-chrome",
-)
-
-chrome_internal_verifier(
-    builder = "win64-chrome",
-)
diff --git a/infra/config/subprojects/chromium/subproject.star b/infra/config/subprojects/chromium/subproject.star
index 1bdd1ff..93619a42 100644
--- a/infra/config/subprojects/chromium/subproject.star
+++ b/infra/config/subprojects/chromium/subproject.star
@@ -2,9 +2,42 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-load("//project.star", "master_only_exec")
+load("//lib/branches.star", "branches")
 
 exec("./ci.star")
 exec("./try.star")
+exec("./gpu.try.star")
+exec("./swangle.try.star")
 
-master_only_exec("./master-only/master-only.star")
+# Execute the M85 config
+branches.exec("./versioned/m85/buckets/ci.star")
+branches.exec("./versioned/m85/buckets/try.star")
+
+# TODO(gbeaty) external_console_view uses new fields/types that aren't present
+# in the version of the protobuf that lint-luci-milo uses, so update protos and
+# then uncomment these (the main console is still reachable via the beta link in
+# the header)
+# luci.external_console_view(
+#     name = "main-m86",
+#     title = "Chromium M86 Main Console",
+#     source = "chromium-m86:main",
+# )
+
+# luci.external_console_view(
+#     name = "mirrors-m86",
+#     title = "Chromium M86 CQ Mirrors Console",
+#     source = "chromium-m86:mirrors",
+# )
+
+# luci.external_console_view(
+#     name = "try-m86",
+#     title = "Chromium M86 CQ Console",
+#     source = "chromium-m86:try",
+# )
+
+branches.exec("./consoles/android.packager.star")
+branches.exec("./consoles/luci.chromium.try.star")
+branches.exec("./consoles/metadata.exporter.star")
+branches.exec("./consoles/sheriff.ios.star")
+
+branches.exec("./fallback-cq.star")
diff --git a/infra/config/subprojects/chromium/master-only/swangle.try.star b/infra/config/subprojects/chromium/swangle.try.star
similarity index 100%
rename from infra/config/subprojects/chromium/master-only/swangle.try.star
rename to infra/config/subprojects/chromium/swangle.try.star
diff --git a/infra/config/subprojects/chromium/try.star b/infra/config/subprojects/chromium/try.star
index 2d664b76..b3e51bc5 100644
--- a/infra/config/subprojects/chromium/try.star
+++ b/infra/config/subprojects/chromium/try.star
@@ -72,6 +72,11 @@
 # them, then lexicographically by their name
 
 try_.blink_builder(
+    name = "linux-blink-optional-highdpi-rel",
+    goma_backend = goma.backend.RBE_PROD,
+)
+
+try_.blink_builder(
     name = "linux-blink-rel",
     branch_selector = branches.STANDARD_RELEASES,
     goma_backend = goma.backend.RBE_PROD,
@@ -86,6 +91,41 @@
     ),
 )
 
+try_.blink_builder(
+    name = "win10-blink-rel",
+    goma_backend = goma.backend.RBE_PROD,
+    os = os.WINDOWS_ANY,
+    builderless = True,
+)
+
+try_.blink_builder(
+    name = "win7-blink-rel",
+    goma_backend = goma.backend.RBE_PROD,
+    os = os.WINDOWS_ANY,
+    builderless = True,
+)
+
+try_.blink_mac_builder(
+    name = "mac10.12-blink-rel",
+)
+
+try_.blink_mac_builder(
+    name = "mac10.13-blink-rel",
+)
+
+try_.blink_mac_builder(
+    name = "mac10.14-blink-rel",
+)
+
+try_.blink_mac_builder(
+    name = "mac10.15-blink-rel",
+)
+
+try_.blink_mac_builder(
+    name = "mac11.0-blink-rel",
+    builderless = False,
+)
+
 try_.chromium_builder(
     name = "android-official",
     branch_selector = branches.STANDARD_RELEASES,
@@ -119,6 +159,18 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-10-arm64-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android-asan",
+)
+
+try_.chromium_android_builder(
+    name = "android-bfcache-rel",
+)
+
+try_.chromium_android_builder(
     name = "android-binary-size",
     branch_selector = branches.STANDARD_RELEASES,
     executable = "recipe:binary_size_trybot",
@@ -159,6 +211,22 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-cronet-marshmallow-arm64-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android-deterministic-dbg",
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+)
+
+try_.chromium_android_builder(
+    name = "android-deterministic-rel",
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+)
+
+try_.chromium_android_builder(
     name = "android-lollipop-arm-rel",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -178,6 +246,10 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-marshmallow-x86-fyi-rel",
+)
+
+try_.chromium_android_builder(
     name = "android-marshmallow-x86-rel",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -196,6 +268,18 @@
 #)
 
 try_.chromium_android_builder(
+    name = "android-opus-arm-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android-oreo-arm64-cts-networkservice-dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android-oreo-arm64-dbg",
+)
+
+try_.chromium_android_builder(
     name = "android-pie-arm64-dbg",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J300,
@@ -229,6 +313,70 @@
 )
 
 try_.chromium_android_builder(
+    name = "android-pie-x86-rel",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_android_builder(
+    name = "android-pie-arm64-coverage-rel",
+    cores = 16,
+    goma_jobs = goma.jobs.J300,
+    ssd = True,
+    use_clang_coverage = True,
+)
+
+try_.chromium_android_builder(
+    name = "android-weblayer-pie-arm64-fyi-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android-weblayer-pie-x86-fyi-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android-webview-marshmallow-arm64-dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android-webview-nougat-arm64-dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android-webview-oreo-arm64-dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android-webview-pie-arm64-dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android-webview-pie-arm64-fyi-rel",
+)
+
+try_.chromium_android_builder(
+    name = "android_archive_rel_ng",
+)
+
+try_.chromium_android_builder(
+    name = "android_arm64_dbg_recipe",
+    goma_jobs = goma.jobs.J300,
+)
+
+try_.chromium_android_builder(
+    name = "android_blink_rel",
+)
+
+try_.chromium_android_builder(
+    name = "android_cfi_rel_ng",
+    cores = 32,
+)
+
+try_.chromium_android_builder(
+    name = "android_clang_dbg_recipe",
+    goma_jobs = goma.jobs.J300,
+)
+
+try_.chromium_android_builder(
     name = "android_compile_dbg",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -280,12 +428,102 @@
 )
 
 try_.chromium_android_builder(
+    name = "android_mojo",
+)
+
+try_.chromium_android_builder(
+    name = "android_n5x_swarming_dbg",
+)
+
+try_.chromium_android_builder(
+    name = "android_unswarmed_pixel_aosp",
+)
+
+try_.chromium_android_builder(
     name = "cast_shell_android",
     branch_selector = branches.STANDARD_RELEASES,
     main_list_view = settings.main_list_view_name,
     tryjob = try_.job(),
 )
 
+try_.chromium_android_builder(
+    name = "linux_android_dbg_ng",
+)
+
+try_.chromium_android_builder(
+    name = "try-nougat-phone-tester",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_deqp_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_vk32_deqp_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_vk32_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_vk64_deqp_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "android_angle_vk64_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "fuchsia-angle-rel",
+)
+
+try_.chromium_angle_builder(
+    name = "linux-angle-rel",
+)
+
+try_.chromium_angle_builder(
+    name = "linux_angle_deqp_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "linux_angle_ozone_rel_ng",
+)
+
+try_.chromium_angle_builder(
+    name = "mac-angle-rel",
+    cores = None,
+    os = os.MAC_ANY,
+)
+
+try_.chromium_angle_builder(
+    name = "win-angle-deqp-rel-32",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_angle_builder(
+    name = "win-angle-deqp-rel-64",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_angle_builder(
+    name = "win-angle-rel-32",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_angle_builder(
+    name = "win-angle-rel-64",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_chromiumos_builder(
+    name = "chromeos-amd64-generic-cfi-thin-lto-rel",
+)
+
 try_.chromium_chromiumos_builder(
     name = "chromeos-amd64-generic-dbg",
     branch_selector = branches.STANDARD_RELEASES,
@@ -306,6 +544,10 @@
 )
 
 try_.chromium_chromiumos_builder(
+    name = "chromeos-arm-generic-dbg",
+)
+
+try_.chromium_chromiumos_builder(
     name = "chromeos-arm-generic-rel",
     branch_selector = branches.STANDARD_RELEASES,
     main_list_view = settings.main_list_view_name,
@@ -320,6 +562,22 @@
 )
 
 try_.chromium_chromiumos_builder(
+    name = "chromeos-kevin-compile-rel",
+)
+
+try_.chromium_chromiumos_builder(
+    name = "chromeos-kevin-rel",
+    main_list_view = settings.main_list_view_name,
+    tryjob = try_.job(
+        location_regexp = [
+            ".+/[+]/build/chromeos/.+",
+            ".+/[+]/build/config/chromeos/.*",
+            ".+/[+]/chromeos/CHROMEOS_LKGM",
+        ],
+    ),
+)
+
+try_.chromium_chromiumos_builder(
     name = "linux-chromeos-rel",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -328,6 +586,16 @@
     use_clang_coverage = True,
 )
 
+try_.chromium_chromiumos_builder(
+    name = "linux-lacros-rel",
+    main_list_view = settings.main_list_view_name,
+    tryjob = try_.job(),
+)
+
+try_.chromium_chromiumos_builder(
+    name = "linux-chromeos-dbg",
+)
+
 try_.chromium_dawn_builder(
     name = "dawn-linux-x64-deps-rel",
     branch_selector = branches.STANDARD_RELEASES,
@@ -407,6 +675,34 @@
     ),
 )
 
+try_.chromium_dawn_builder(
+    name = "linux-dawn-rel",
+)
+
+try_.chromium_dawn_builder(
+    name = "mac-dawn-rel",
+    os = os.MAC_ANY,
+)
+
+try_.chromium_dawn_builder(
+    name = "win-dawn-rel",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_dawn_builder(
+    name = "dawn-try-win10-x86-rel",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_dawn_builder(
+    name = "dawn-try-win10-x64-asan-rel",
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_linux_builder(
+    name = "cast_shell_audio_linux",
+)
+
 try_.chromium_linux_builder(
     name = "cast_shell_linux",
     branch_selector = branches.STANDARD_RELEASES,
@@ -457,6 +753,29 @@
 )
 
 try_.chromium_linux_builder(
+    name = "fuchsia-compile-x64-dbg",
+    tryjob = try_.job(
+        experiment_percentage = 50,
+    ),
+)
+
+try_.chromium_linux_builder(
+    name = "fuchsia-fyi-arm64-dbg",
+)
+
+try_.chromium_linux_builder(
+    name = "fuchsia-fyi-arm64-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "fuchsia-fyi-x64-dbg",
+)
+
+try_.chromium_linux_builder(
+    name = "fuchsia-fyi-x64-rel",
+)
+
+try_.chromium_linux_builder(
     name = "fuchsia-x64-cast",
     branch_selector = branches.STANDARD_RELEASES,
     main_list_view = settings.main_list_view_name,
@@ -478,6 +797,67 @@
 )
 
 try_.chromium_linux_builder(
+    name = "layout_test_leak_detection",
+)
+
+try_.chromium_linux_builder(
+    name = "leak_detection_linux",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-annotator-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-autofill-assistant",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-bfcache-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-blink-heap-concurrent-marking-tsan-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-blink-heap-verification-try",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-clang-tidy-dbg",
+    executable = "recipe:tricium_clang_tidy_wrapper",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_linux_builder(
+    name = "linux-clang-tidy-rel",
+    executable = "recipe:tricium_clang_tidy_wrapper",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_linux_builder(
+    name = "linux-dcheck-off-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-gcc-rel",
+    goma_backend = None,
+)
+
+try_.chromium_linux_builder(
+    name = "linux-lacros-fyi-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-layout-tests-edit-ng",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-layout-tests-fragment-item",
+)
+
+try_.chromium_linux_builder(
     name = "linux-libfuzzer-asan-rel",
     branch_selector = branches.STANDARD_RELEASES,
     executable = "recipe:chromium_libfuzzer_trybot",
@@ -493,6 +873,20 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux-perfetto-rel",
+    tryjob = try_.job(
+        experiment_percentage = 100,
+        location_regexp = [
+            ".+/[+]/base/trace_event/.+",
+            ".+/[+]/base/tracing/.+",
+            ".+/[+]/components/tracing/.+",
+            ".+/[+]/content/browser/tracing/.+",
+            ".+/[+]/services/tracing/.+",
+        ],
+    ),
+)
+
+try_.chromium_linux_builder(
     name = "linux-rel",
     branch_selector = branches.STANDARD_RELEASES,
     # TODO(https://crbug.com/1109276) Once support for mastername is removed, do
@@ -505,15 +899,70 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux-trusty-rel",
+    goma_jobs = goma.jobs.J150,
+    os = os.LINUX_TRUSTY,
+)
+
+try_.chromium_linux_builder(
+    name = "linux-viz-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-webkit-msan-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux-wpt-fyi-rel",
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_analysis",
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_archive_rel_ng",
+)
+
+try_.chromium_linux_builder(
     name = "linux_chromium_asan_rel_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
-    main_list_view = settings.main_list_view_name,
     ssd = True,
+    main_list_view = settings.main_list_view_name,
     tryjob = try_.job(),
 )
 
 try_.chromium_linux_builder(
+    name = "linux_chromium_cfi_rel_ng",
+    cores = 32,
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_chromeos_asan_rel_ng",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_chromeos_msan_rel_ng",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_clobber_deterministic",
+    executable = "recipe:swarming/deterministic_build",
+    execution_timeout = 6 * time.hour,
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_clobber_rel_ng",
+)
+
+try_.chromium_linux_builder(
+    name = "linux_chromium_compile_dbg_32_ng",
+)
+
+try_.chromium_linux_builder(
     name = "linux_chromium_compile_dbg_ng",
     branch_selector = branches.STANDARD_RELEASES,
     caches = [
@@ -528,6 +977,10 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux_chromium_compile_rel_ng",
+)
+
+try_.chromium_linux_builder(
     name = "linux_chromium_dbg_ng",
     branch_selector = branches.STANDARD_RELEASES,
     caches = [
@@ -545,6 +998,11 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux_chromium_msan_rel_ng",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_linux_builder(
     name = "linux_chromium_tsan_rel_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -553,6 +1011,10 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux_chromium_ubsan_rel_ng",
+)
+
+try_.chromium_linux_builder(
     name = "linux_layout_tests_composite_after_paint",
     branch_selector = branches.STANDARD_RELEASES,
     main_list_view = settings.main_list_view_name,
@@ -585,6 +1047,23 @@
 )
 
 try_.chromium_linux_builder(
+    name = "linux_mojo",
+)
+
+try_.chromium_linux_builder(
+    name = "linux_mojo_chromeos",
+)
+
+try_.chromium_linux_builder(
+    name = "linux_upload_clang",
+    builderless = True,
+    cores = 32,
+    executable = "recipe:chromium_upload_clang",
+    goma_backend = None,
+    os = os.LINUX_TRUSTY,
+)
+
+try_.chromium_linux_builder(
     name = "linux_vr",
     branch_selector = branches.STANDARD_RELEASES,
     main_list_view = settings.main_list_view_name,
@@ -596,6 +1075,27 @@
     ),
 )
 
+try_.chromium_linux_builder(
+    name = "network_service_linux",
+)
+
+try_.chromium_linux_builder(
+    name = "tricium-metrics-analysis",
+    executable = "recipe:tricium_metrics",
+)
+
+try_.chromium_mac_builder(
+    name = "mac-coverage-rel",
+    use_clang_coverage = True,
+    goma_jobs = goma.jobs.J150,
+    tryjob = try_.job(experiment_percentage = 5),
+)
+
+try_.chromium_mac_builder(
+    name = "mac-osxbeta-rel",
+    os = os.MAC_DEFAULT,
+)
+
 try_.chromium_mac_builder(
     name = "mac-rel",
     branch_selector = branches.STANDARD_RELEASES,
@@ -612,15 +1112,84 @@
     os = os.MAC_10_15,
 )
 
+# NOTE: the following trybots aren't sensitive to Mac version on which
+# they are built, hence no additional dimension is specified.
+# The 10.xx version translates to which bots will run isolated tests.
+try_.chromium_mac_builder(
+    name = "mac_chromium_10.10",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_10.12_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_10.13_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_10.14_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_10.15_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_11.0_rel_ng",
+    builderless = False,
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_archive_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_asan_rel_ng",
+    goma_jobs = goma.jobs.J150,
+)
+
 try_.chromium_mac_builder(
     name = "mac_chromium_compile_dbg_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
-    main_list_view = settings.main_list_view_name,
     os = os.MAC_10_13,
+    main_list_view = settings.main_list_view_name,
     tryjob = try_.job(),
 )
 
+try_.chromium_mac_builder(
+    name = "mac_chromium_compile_rel_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_chromium_dbg_ng",
+)
+
+try_.chromium_mac_builder(
+    name = "mac_upload_clang",
+    builderless = False,
+    caches = [
+        swarming.cache(
+            name = "xcode_mac_9a235",
+            path = "xcode_mac_9a235.app",
+        ),
+    ],
+    executable = "recipe:chromium_upload_clang",
+    execution_timeout = 6 * time.hour,
+    goma_backend = None,  # Does not use Goma.
+    properties = {
+        "$depot_tools/osx_sdk": {
+            "sdk_version": "9a235",
+        },
+    },
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios-device",
+    executable = "recipe:chromium_trybot",
+)
+
 try_.chromium_mac_ios_builder(
     name = "ios-simulator",
     branch_selector = branches.STANDARD_RELEASES,
@@ -633,6 +1202,24 @@
 )
 
 try_.chromium_mac_ios_builder(
+    name = "ios-simulator-code-coverage",
+    executable = "recipe:chromium_trybot",
+    use_clang_coverage = True,
+    coverage_exclude_sources = "ios_test_files_and_test_utils",
+    coverage_test_types = ["unit"],
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+    tryjob = try_.job(experiment_percentage = 3),
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios-simulator-cr-recipe",
+    executable = "recipe:chromium_trybot",
+)
+
+try_.chromium_mac_ios_builder(
     name = "ios-simulator-cronet",
     branch_selector = branches.STANDARD_RELEASES,
     caches = [xcode_cache.x11e146],
@@ -654,6 +1241,10 @@
 )
 
 try_.chromium_mac_ios_builder(
+    name = "ios-simulator-eg",
+)
+
+try_.chromium_mac_ios_builder(
     name = "ios-simulator-full-configs",
     branch_selector = branches.STANDARD_RELEASES,
     executable = "recipe:chromium_trybot",
@@ -665,6 +1256,76 @@
     ),
 )
 
+try_.chromium_mac_ios_builder(
+    name = "ios-simulator-multi-window",
+    executable = "recipe:chromium_trybot",
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios-simulator-noncq",
+    executable = "recipe:chromium_trybot",
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios13-beta-simulator",
+    executable = "recipe:chromium_trybot",
+    caches = [xcode_cache.x12a8189n],
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios13-sdk-simulator",
+    executable = "recipe:chromium_trybot",
+    caches = [xcode_cache.x12a8189n],
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios14-beta-simulator",
+    executable = "recipe:chromium_trybot",
+    caches = [xcode_cache.x12a8189n],
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+try_.chromium_mac_ios_builder(
+    name = "ios14-sdk-simulator",
+    executable = "recipe:chromium_trybot",
+    caches = [xcode_cache.x12a8189n],
+    os = os.MAC_10_15,
+    properties = {
+        "xcode_build_version": "12a8189n",
+    },
+)
+
+try_.chromium_win_builder(
+    name = "win-annotator-rel",
+)
+
+try_.chromium_win_builder(
+    name = "win-asan",
+    goma_jobs = goma.jobs.J150,
+)
+
+try_.chromium_win_builder(
+    name = "win-celab-try-rel",
+    executable = "recipe:celab",
+    properties = {
+        "exclude": "chrome_only",
+        "pool_name": "celab-chromium-try",
+        "pool_size": 20,
+        "tests": "*",
+    },
+)
+
 try_.chromium_win_builder(
     name = "win-libfuzzer-asan-rel",
     branch_selector = branches.STANDARD_RELEASES,
@@ -676,6 +1337,10 @@
 )
 
 try_.chromium_win_builder(
+    name = "win_archive",
+)
+
+try_.chromium_win_builder(
     name = "win_chromium_compile_dbg_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
@@ -684,17 +1349,57 @@
 )
 
 try_.chromium_win_builder(
+    name = "win_chromium_compile_rel_ng",
+)
+
+try_.chromium_win_builder(
+    name = "win_chromium_dbg_ng",
+)
+
+try_.chromium_win_builder(
+    name = "win_chromium_x64_rel_ng",
+)
+
+try_.chromium_win_builder(
+    name = "win_mojo",
+)
+
+try_.chromium_win_builder(
+    name = "win_upload_clang",
+    builderless = False,
+    cores = 32,
+    executable = "recipe:chromium_upload_clang",
+    goma_backend = None,
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_win_builder(
+    name = "win_x64_archive",
+)
+
+try_.chromium_win_builder(
+    name = "win10_chromium_x64_dbg_ng",
+    os = os.WINDOWS_10,
+)
+
+try_.chromium_win_builder(
     name = "win10_chromium_x64_rel_ng",
     branch_selector = branches.STANDARD_RELEASES,
     goma_jobs = goma.jobs.J150,
-    main_list_view = settings.main_list_view_name,
     os = os.WINDOWS_10,
     ssd = True,
     use_clang_coverage = True,
+    main_list_view = settings.main_list_view_name,
     tryjob = try_.job(cancel_stale = False),
 )
 
 try_.chromium_win_builder(
+    name = "win10_chromium_x64_rel_ng_exp",
+    builderless = False,
+    os = os.WINDOWS_ANY,
+)
+
+try_.chromium_win_builder(
     name = "win7-rel",
     branch_selector = branches.STANDARD_RELEASES,
     execution_timeout = 4 * time.hour + 30 * time.minute,
@@ -819,22 +1524,65 @@
         *,
         builder,
         **kwargs):
-    luci.cq_tryjob_verifier(
+    branches.cq_tryjob_verifier(
         builder = "chrome:try/" + builder,
-        cq_group = settings.cq_group,
+        cq_group = "cq",
         includable_only = True,
         owner_whitelist = [
             "googlers",
             "project-chromium-robot-committers",
         ],
+        **kwargs
     )
 
 chrome_internal_verifier(
+    builder = "chromeos-betty-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "chromeos-betty-pi-arc-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "chromeos-eve-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "chromeos-eve-compile-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "chromeos-kevin-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "chromeos-kevin-compile-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "ipad-device",
+)
+
+chrome_internal_verifier(
+    builder = "iphone-device",
+)
+
+chrome_internal_verifier(
     builder = "linux-chrome-beta",
+    branch_selector = branches.STANDARD_RELEASES,
 )
 
 chrome_internal_verifier(
     builder = "linux-chrome-stable",
+    branch_selector = branches.STANDARD_RELEASES,
+)
+
+chrome_internal_verifier(
+    builder = "linux-chromeos-chrome",
+)
+
+chrome_internal_verifier(
+    builder = "mac-chrome",
 )
 
 chrome_internal_verifier(
@@ -848,6 +1596,10 @@
 )
 
 chrome_internal_verifier(
+    builder = "win-chrome",
+)
+
+chrome_internal_verifier(
     builder = "win-chrome-beta",
     branch_selector = branches.STANDARD_RELEASES,
 )
@@ -858,6 +1610,10 @@
 )
 
 chrome_internal_verifier(
+    builder = "win64-chrome",
+)
+
+chrome_internal_verifier(
     builder = "win64-chrome-beta",
     branch_selector = branches.STANDARD_RELEASES,
 )
diff --git a/ios/chrome/app/chrome_overlay_window.mm b/ios/chrome/app/chrome_overlay_window.mm
index 26a88ee3b..cfc1780ac 100644
--- a/ios/chrome/app/chrome_overlay_window.mm
+++ b/ios/chrome/app/chrome_overlay_window.mm
@@ -73,9 +73,9 @@
 
 - (void)setFrame:(CGRect)rect {
   if (@available(iOS 13, *)) {
-    if (!IsIPadIdiom() && (rect.origin.x < 0 || rect.origin.y < 0)) {
+    if (!IsIPadIdiom() && (rect.origin.x != 0 || rect.origin.y != 0)) {
       // skip, this rect is wrong and probably in portrait while
-      // display is in landscape.
+      // display is in landscape or vice-versa.
     } else {
       [super setFrame:rect];
     }
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index 594081c..22dd570 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -86,6 +86,9 @@
     V4L2_PIX_FMT_H264_SLICE, V4L2_PIX_FMT_VP8_FRAME, V4L2_PIX_FMT_VP9_FRAME,
 };
 
+// static
+base::AtomicRefCount V4L2SliceVideoDecodeAccelerator::num_instances_(0);
+
 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord()
     : picture_id(-1),
       texture_id(0),
@@ -146,7 +149,8 @@
     EGLDisplay egl_display,
     const BindGLImageCallback& bind_image_cb,
     const MakeGLContextCurrentCallback& make_context_current_cb)
-    : output_planes_count_(0),
+    : can_use_decoder_(num_instances_.Increment() < kMaxNumOfInstances),
+      output_planes_count_(0),
       child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       device_(std::move(device)),
       decoder_thread_("V4L2SliceVideoDecodeAcceleratorThread"),
@@ -174,6 +178,8 @@
 
   DCHECK(requests_.empty());
   DCHECK(output_buffer_map_.empty());
+
+  num_instances_.Decrement();
 }
 
 void V4L2SliceVideoDecodeAccelerator::NotifyError(Error error) {
@@ -198,6 +204,11 @@
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kUninitialized);
 
+  if (!can_use_decoder_) {
+    VLOGF(1) << "Reached the maximum number of decoder instances";
+    return false;
+  }
+
   if (config.is_encrypted()) {
     NOTREACHED() << "Encrypted streams are not supported for this VDA";
     return false;
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
index ec1ba44..6c9fac3 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
@@ -356,6 +356,15 @@
   // Returns whether |profile| is supported by a v4l2 decoder driver.
   bool IsSupportedProfile(VideoCodecProfile profile);
 
+  // TODO(crbug.com/1109312): some pages with lots of small videos are causing
+  // crashes, so limit the number of simultaneous decoder instances for now.
+  // |num_instances_| tracks the number of simultaneous decoders.
+  // |can_use_decoder_| is true iff we haven't reached the maximum number of
+  // instances at the time this decoder is created.
+  static constexpr int kMaxNumOfInstances = 10;
+  static base::AtomicRefCount num_instances_;
+  const bool can_use_decoder_;
+
   // VideoCodecProfiles supported by a v4l2 decoder driver.
   std::vector<VideoCodecProfile> supported_profiles_;
 
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index e844687..5147890 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -76,6 +76,9 @@
     V4L2_PIX_FMT_H264, V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9,
 };
 
+// static
+base::AtomicRefCount V4L2VideoDecodeAccelerator::num_instances_(0);
+
 struct V4L2VideoDecodeAccelerator::BitstreamBufferRef {
   BitstreamBufferRef(
       base::WeakPtr<Client>& client,
@@ -132,7 +135,8 @@
     const GetGLContextCallback& get_gl_context_cb,
     const MakeGLContextCurrentCallback& make_context_current_cb,
     scoped_refptr<V4L2Device> device)
-    : child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+    : can_use_decoder_(num_instances_.Increment() < kMaxNumOfInstances),
+      child_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       decoder_thread_("V4L2DecoderThread"),
       decoder_state_(kUninitialized),
       output_mode_(Config::OutputMode::ALLOCATE),
@@ -162,6 +166,8 @@
   // These maps have members that should be manually destroyed, e.g. file
   // descriptors, mmap() segments, etc.
   DCHECK(output_buffer_map_.empty());
+
+  num_instances_.Decrement();
 }
 
 bool V4L2VideoDecodeAccelerator::Initialize(const Config& config,
@@ -171,6 +177,11 @@
   DCHECK(child_task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(decoder_state_, kUninitialized);
 
+  if (!can_use_decoder_) {
+    VLOGF(1) << "Reached the maximum number of decoder instances";
+    return false;
+  }
+
   if (config.is_encrypted()) {
     NOTREACHED() << "Encrypted streams are not supported for this VDA";
     return false;
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.h b/media/gpu/v4l2/v4l2_video_decode_accelerator.h
index 96a2351..1460737b 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.h
@@ -431,6 +431,15 @@
   // Image processor notifies an error.
   void ImageProcessorError();
 
+  // TODO(crbug.com/1109312): some pages with lots of small videos are causing
+  // crashes, so limit the number of simultaneous decoder instances for now.
+  // |num_instances_| tracks the number of simultaneous decoders.
+  // |can_use_decoder_| is true iff we haven't reached the maximum number of
+  // instances at the time this decoder is created.
+  static constexpr int kMaxNumOfInstances = 10;
+  static base::AtomicRefCount num_instances_;
+  const bool can_use_decoder_;
+
   // Our original calling task runner for the child thread.
   scoped_refptr<base::SingleThreadTaskRunner> child_task_runner_;
 
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc
index 3cdb8dc..9e71ae0 100644
--- a/media/video/vpx_video_encoder.cc
+++ b/media/video/vpx_video_encoder.cc
@@ -140,11 +140,18 @@
       codec_config_.g_input_bit_depth = 8;
       break;
   }
-  vpx_image_ =
-      vpx_img_wrap(nullptr, img_fmt, options.width, options.height, 1, nullptr);
-  vpx_image_->bit_depth = bits_for_storage;
 
-  auto status = SetUpVpxConfig(options, &codec_config_);
+  Status status;
+  if (&vpx_image_ != vpx_img_wrap(&vpx_image_, img_fmt, options.width,
+                                  options.height, 1, nullptr)) {
+    status = Status(StatusCode::kEncoderInitializationError,
+                    "Invalid format or frame size.");
+    std::move(done_cb).Run(status);
+    return;
+  }
+  vpx_image_.bit_depth = bits_for_storage;
+
+  status = SetUpVpxConfig(options, &codec_config_);
   if (!status.is_ok()) {
     std::move(done_cb).Run(status);
     return;
@@ -230,29 +237,29 @@
           frame->stride(media::VideoFrame::kUPlane),
           frame->visible_data(media::VideoFrame::kVPlane),
           frame->stride(media::VideoFrame::kVPlane),
-          reinterpret_cast<uint16_t*>(vpx_image_->planes[VPX_PLANE_Y]),
-          vpx_image_->stride[VPX_PLANE_Y] / 2,
-          reinterpret_cast<uint16_t*>(vpx_image_->planes[VPX_PLANE_U]),
-          vpx_image_->stride[VPX_PLANE_U] / 2,
-          reinterpret_cast<uint16_t*>(vpx_image_->planes[VPX_PLANE_V]),
-          vpx_image_->stride[VPX_PLANE_V] / 2, frame->coded_size().width(),
+          reinterpret_cast<uint16_t*>(vpx_image_.planes[VPX_PLANE_Y]),
+          vpx_image_.stride[VPX_PLANE_Y] / 2,
+          reinterpret_cast<uint16_t*>(vpx_image_.planes[VPX_PLANE_U]),
+          vpx_image_.stride[VPX_PLANE_U] / 2,
+          reinterpret_cast<uint16_t*>(vpx_image_.planes[VPX_PLANE_V]),
+          vpx_image_.stride[VPX_PLANE_V] / 2, frame->coded_size().width(),
           frame->coded_size().height());
       break;
     case media::VP9PROFILE_PROFILE3:
       NOTREACHED();
       break;
     default:
-      vpx_image_->planes[VPX_PLANE_Y] =
+      vpx_image_.planes[VPX_PLANE_Y] =
           const_cast<uint8_t*>(frame->visible_data(media::VideoFrame::kYPlane));
-      vpx_image_->planes[VPX_PLANE_U] =
+      vpx_image_.planes[VPX_PLANE_U] =
           const_cast<uint8_t*>(frame->visible_data(media::VideoFrame::kUPlane));
-      vpx_image_->planes[VPX_PLANE_V] =
+      vpx_image_.planes[VPX_PLANE_V] =
           const_cast<uint8_t*>(frame->visible_data(media::VideoFrame::kVPlane));
-      vpx_image_->stride[VPX_PLANE_Y] =
+      vpx_image_.stride[VPX_PLANE_Y] =
           frame->stride(media::VideoFrame::kYPlane);
-      vpx_image_->stride[VPX_PLANE_U] =
+      vpx_image_.stride[VPX_PLANE_U] =
           frame->stride(media::VideoFrame::kUPlane);
-      vpx_image_->stride[VPX_PLANE_V] =
+      vpx_image_.stride[VPX_PLANE_V] =
           frame->stride(media::VideoFrame::kVPlane);
       break;
   }
@@ -261,7 +268,7 @@
   auto duration = GetFrameDuration(*frame);
   auto deadline = VPX_DL_REALTIME;
   vpx_codec_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
-  auto vpx_error = vpx_codec_encode(codec_, vpx_image_, timestamp, duration,
+  auto vpx_error = vpx_codec_encode(codec_, &vpx_image_, timestamp, duration,
                                     flags, deadline);
 
   if (vpx_error != VPX_CODEC_OK) {
@@ -319,10 +326,10 @@
   DCHECK_EQ(error, VPX_CODEC_OK);
   delete codec_;
 
-  if (vpx_image_ != nullptr) {
-    vpx_img_free(vpx_image_);
-    vpx_image_ = nullptr;
-  }
+  // It's safe to call vpx_img_free, even if vpx_image_ has never been
+  // initialized. vpx_img_free is not going to deallocate the vpx_image_
+  // itself, only internal buffers.
+  vpx_img_free(&vpx_image_);
 }
 
 void VpxVideoEncoder::Flush(StatusCB done_cb) {
diff --git a/media/video/vpx_video_encoder.h b/media/video/vpx_video_encoder.h
index 4b9ea428..63ccbd1 100644
--- a/media/video/vpx_video_encoder.h
+++ b/media/video/vpx_video_encoder.h
@@ -38,7 +38,7 @@
   vpx_codec_ctx_t* codec_ = nullptr;
   bool is_vp9_ = false;
   vpx_codec_enc_cfg_t codec_config_ = {};
-  vpx_image_t* vpx_image_ = nullptr;
+  vpx_image_t vpx_image_ = {};
   VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
   Options options_;
   OutputCB output_cb_;
diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java
index 5df999d..8cfd930 100644
--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java
+++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/AutoCloseableRouter.java
@@ -114,12 +114,11 @@
                 @Override
                 public void run() {
                     close();
-                    throw new IllegalStateException(
-                            "Warning: Router objects should be explicitly closed "
-                                    + "when no longer required otherwise you may leak handles.",
-                            mAllocationException);
                 }
             });
+            throw new IllegalStateException("Warning: Router objects should be explicitly closed "
+                            + "when no longer required otherwise you may leak handles.",
+                    mAllocationException);
         }
         super.finalize();
     }
diff --git a/net/cert/internal/revocation_util_unittest.cc b/net/cert/internal/revocation_util_unittest.cc
index 9b8fcbb4..40a1f02 100644
--- a/net/cert/internal/revocation_util_unittest.cc
+++ b/net/cert/internal/revocation_util_unittest.cc
@@ -5,7 +5,6 @@
 #include "net/cert/internal/revocation_util.h"
 
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "net/der/encode_values.h"
 #include "net/der/parse_values.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -138,13 +137,15 @@
   der::GeneralizedTime encoded_this_update;
   ASSERT_TRUE(
       der::EncodeTimeAsGeneralizedTime(this_update, &encoded_this_update));
-#if defined(OS_WIN)
-  EXPECT_FALSE(CheckRevocationDateValid(encoded_this_update, nullptr,
-                                        verify_time, kOneWeek));
-#else
-  EXPECT_TRUE(CheckRevocationDateValid(encoded_this_update, nullptr,
-                                       verify_time, kOneWeek));
-#endif
+  // Note: Not all platforms can explode Time before the Windows Epoch. So,
+  // CheckRevocationDateValid() should succeed iff UTCExplode() will also
+  // succeed for a Time 6 days before the Windows Epoch.
+  base::Time::Exploded exploded;
+  (verify_time - kOneWeek).UTCExplode(&exploded);
+  const bool can_encode_before_windows_epoch = exploded.HasValidValues();
+  EXPECT_EQ(can_encode_before_windows_epoch,
+            CheckRevocationDateValid(encoded_this_update, nullptr, verify_time,
+                                     kOneWeek));
 }
 
 }  // namespace net
diff --git a/net/der/encode_values_unittest.cc b/net/der/encode_values_unittest.cc
index 6301d34..fd964ef 100644
--- a/net/der/encode_values_unittest.cc
+++ b/net/der/encode_values_unittest.cc
@@ -41,33 +41,25 @@
 // after the 32-bit time_t maximum, the conversion between base::Time and
 // der::GeneralizedTime goes through the time representation of the underlying
 // platform, which might not be able to handle the full GeneralizedTime date
-// range. Out-of-range times should not be converted to der::GeneralizedTime. In
-// tests, possibly-out-of-range test times are specified as a
-// base::Time::Exploded, and then converted to a base::Time. If the conversion
-// fails, this signals the underlying platform cannot handle the time, and the
-// test aborts early. If the underlying platform can represent the time, then
-// the conversion is successful, and the encoded GeneralizedTime can should
-// match the test time.
+// range. Out-of-range times should not be converted to der::GeneralizedTime.
 //
-// Thu, 1 Jan 1570 00:00:00 GMT. This time is unrepresentable by the Windows
-// native time libraries.
+// Thus, this test focuses on an input date 31 years before the Windows epoch,
+// and confirms that EncodeTimeAsGeneralizedTime() produces the correct result
+// on platforms where it returns true. As of this writing, it will return false
+// on Windows.
 TEST(EncodeValuesTest, EncodeTimeFromBeforeWindowsEpoch) {
-  base::Time::Exploded exploded;
-  exploded.year = 1570;
-  exploded.month = 1;
-  exploded.day_of_week = 5;
-  exploded.day_of_month = 1;
-  exploded.hour = 0;
-  exploded.minute = 0;
-  exploded.second = 0;
-  exploded.millisecond = 0;
-
-  base::Time time;
-  if (!base::Time::FromUTCExploded(exploded, &time))
-    return;
+  constexpr int kYearsBeforeWindowsEpoch = 1601 - 1570;
+  constexpr int kDaysPerYear = 365;
+  constexpr int kExtraLeapDaysOverThoseYears = 8;
+  constexpr base::Time kStartOfYear1570 =
+      base::Time() -
+      base::TimeDelta::FromDays(kYearsBeforeWindowsEpoch * kDaysPerYear +
+                                kExtraLeapDaysOverThoseYears);
 
   GeneralizedTime generalized_time;
-  ASSERT_TRUE(EncodeTimeAsGeneralizedTime(time, &generalized_time));
+  if (!EncodeTimeAsGeneralizedTime(kStartOfYear1570, &generalized_time))
+    return;
+
   EXPECT_EQ(1570, generalized_time.year);
   EXPECT_EQ(1, generalized_time.month);
   EXPECT_EQ(1, generalized_time.day);
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc
index 0e97f63c..17b0895 100644
--- a/net/quic/quic_chromium_client_session_test.cc
+++ b/net/quic/quic_chromium_client_session_test.cc
@@ -1111,7 +1111,7 @@
 
   // Close a stream and ensure I can now open a new one.
   quic::QuicStreamId stream_id = streams[0]->id();
-  session_->CloseStream(stream_id);
+  session_->ResetStream(stream_id, quic::QUIC_RST_ACKNOWLEDGEMENT);
 
   // Pump data, bringing in the max-stream-id
   base::RunLoop().RunUntilIdle();
@@ -1302,7 +1302,7 @@
   quic::QuicStreamFrame data(id, false, 1, quiche::QuicheStringPiece("SP"));
   session_->OnStreamFrame(data);
   EXPECT_EQ(0u, session_->GetNumActiveStreams());
-  session_->CloseStream(id);
+  session_->ResetStream(id, quic::QUIC_STREAM_NO_ERROR);
 }
 
 TEST_P(QuicChromiumClientSessionTest, CancelPushWhenPendingValidation) {
@@ -1362,7 +1362,8 @@
   EXPECT_TRUE(session_->GetPromisedByUrl(pushed_url.spec()));
 
   // Reset the stream now before tear down.
-  session_->CloseStream(GetNthClientInitiatedBidirectionalStreamId(0));
+  session_->ResetStream(GetNthClientInitiatedBidirectionalStreamId(0),
+                        quic::QUIC_RST_ACKNOWLEDGEMENT);
 }
 
 TEST_P(QuicChromiumClientSessionTest, CancelPushBeforeReceivingResponse) {
@@ -1530,7 +1531,7 @@
 
   // Close a stream and ensure I can now open a new one.
   quic::QuicStreamId stream_id = streams[0]->id();
-  session_->CloseStream(stream_id);
+  session_->ResetStream(stream_id, quic::QUIC_RST_ACKNOWLEDGEMENT);
   quic::QuicRstStreamFrame rst1(quic::kInvalidControlFrameId, stream_id,
                                 quic::QUIC_STREAM_NO_ERROR, 0);
   session_->OnRstStream(rst1);
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 6d830eb9..d6edd7a 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -446,3 +446,10 @@
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_enable_mtu_discovery_at_server,
           false)
+
+// If true, while reading an IETF quic packet, start peer migration immediately
+// when detecting the existence of any non-probing frame instead of at the end
+// of the packet.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_start_peer_migration_earlier,
+          false)
diff --git a/printing/backend/cups_ipp_helper_unittest.cc b/printing/backend/cups_ipp_helper_unittest.cc
index 051c42ab..28d99466 100644
--- a/printing/backend/cups_ipp_helper_unittest.cc
+++ b/printing/backend/cups_ipp_helper_unittest.cc
@@ -346,13 +346,17 @@
 
   EXPECT_EQ(6u, caps.advanced_capabilities.size());
   EXPECT_EQ("confirmation-sheet-print", caps.advanced_capabilities[0].name);
-  EXPECT_EQ(base::Value::Type::BOOLEAN, caps.advanced_capabilities[0].type);
+  EXPECT_EQ(AdvancedCapability::Type::kBoolean,
+            caps.advanced_capabilities[0].type);
   EXPECT_EQ("finishings/7", caps.advanced_capabilities[1].name);
-  EXPECT_EQ(base::Value::Type::BOOLEAN, caps.advanced_capabilities[1].type);
+  EXPECT_EQ(AdvancedCapability::Type::kBoolean,
+            caps.advanced_capabilities[1].type);
   EXPECT_EQ("finishings/10", caps.advanced_capabilities[2].name);
-  EXPECT_EQ(base::Value::Type::BOOLEAN, caps.advanced_capabilities[2].type);
+  EXPECT_EQ(AdvancedCapability::Type::kBoolean,
+            caps.advanced_capabilities[2].type);
   EXPECT_EQ("job-message-to-operator", caps.advanced_capabilities[3].name);
-  EXPECT_EQ(base::Value::Type::STRING, caps.advanced_capabilities[3].type);
+  EXPECT_EQ(AdvancedCapability::Type::kString,
+            caps.advanced_capabilities[3].type);
   EXPECT_EQ("output-bin", caps.advanced_capabilities[4].name);
   EXPECT_EQ(2u, caps.advanced_capabilities[4].values.size());
   EXPECT_EQ("print-quality", caps.advanced_capabilities[5].name);
diff --git a/printing/backend/ipp_handlers.cc b/printing/backend/ipp_handlers.cc
index e23f9c6..0fb4706 100644
--- a/printing/backend/ipp_handlers.cc
+++ b/printing/backend/ipp_handlers.cc
@@ -5,7 +5,6 @@
 #include "printing/backend/ipp_handlers.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "base/values.h"
 #include "printing/backend/cups_printer.h"
 
 namespace printing {
@@ -20,7 +19,7 @@
   capabilities->emplace_back();
   AdvancedCapability& capability = capabilities->back();
   capability.name = attribute_name;
-  capability.type = base::Value::Type::STRING;
+  capability.type = AdvancedCapability::Type::kString;
   // TODO(crbug.com/964919): Set defaults.
 }
 
@@ -37,7 +36,7 @@
   capabilities->emplace_back();
   AdvancedCapability& capability = capabilities->back();
   capability.name = attribute_name;
-  capability.type = base::Value::Type::BOOLEAN;
+  capability.type = AdvancedCapability::Type::kBoolean;
   ipp_attribute_t* attr_default = printer.GetDefaultOptionValue(attribute_name);
   capability.default_value = attr_default && ippGetBoolean(attr_default, 0);
 }
@@ -113,7 +112,7 @@
     AdvancedCapability& capability = capabilities->back();
     capability.name =
         std::string(attribute_name) + "/" + base::NumberToString(value);
-    capability.type = base::Value::Type::BOOLEAN;
+    capability.type = AdvancedCapability::Type::kBoolean;
     // TODO(crbug.com/964919): Set defaults.
   }
 }
diff --git a/printing/backend/print_backend.h b/printing/backend/print_backend.h
index fcedaa48..f9ddcad3 100644
--- a/printing/backend/print_backend.h
+++ b/printing/backend/print_backend.h
@@ -16,10 +16,6 @@
 #include "printing/printing_export.h"
 #include "ui/gfx/geometry/size.h"
 
-#if defined(OS_CHROMEOS)
-#include "base/values.h"
-#endif  // defined(OS_CHROMEOS)
-
 namespace base {
 class DictionaryValue;
 }
@@ -66,6 +62,8 @@
   AdvancedCapability(const AdvancedCapability& other);
   ~AdvancedCapability();
 
+  enum class Type : uint8_t { kNone = 0, kBoolean, kFloat, kInteger, kString };
+
   // IPP identifier of the attribute.
   std::string name;
 
@@ -73,7 +71,7 @@
   std::string display_name;
 
   // Attribute type.
-  base::Value::Type type;
+  AdvancedCapability::Type type;
 
   // Default value.
   std::string default_value;
diff --git a/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter b/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
index 469844f1..72a5f91a 100644
--- a/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/android.emulator_p.chrome_public_test_apk.filter
@@ -75,9 +75,6 @@
 # crbug.com/1061214
 -org.chromium.chrome.browser.customtabs.CustomTabActivityTest.testHiddenTabAndChangingFragmentDontWait
 
-# crbug.com/1061216
--org.chromium.chrome.browser.gesturenav.NavigationHandlerTest.testRightSwipeNavigateForwardOnNativePage
-
 # crbug.com/1058877
 -org.chromium.chrome.browser.autofill.AutofillUpstreamTest.testSaveCardInfoBarContinueButton_EmptyExpDate_launchesExpDateFixFlow
 -org.chromium.chrome.browser.autofill.AutofillUpstreamTest.testSaveCardInfoBarContinueButton_EmptyName_launchesNameFixFlow
diff --git a/third_party/blink/public/devtools_protocol/browser_protocol.pdl b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
index 8d52bd1..cef3dbe 100644
--- a/third_party/blink/public/devtools_protocol/browser_protocol.pdl
+++ b/third_party/blink/public/devtools_protocol/browser_protocol.pdl
@@ -5050,6 +5050,12 @@
       # Map with extra HTTP headers.
       Headers headers
 
+  # Specifies whether to sned a debug header to all outgoing requests.
+  experimental command setAttachDebugHeader
+    parameters
+      # Whether to send a debug header.
+      boolean enabled
+
   # Sets the requests to intercept that match the provided patterns and optionally resource types.
   # Deprecated, please use Fetch.enable instead.
   experimental deprecated command setRequestInterception
diff --git a/third_party/blink/public/mojom/use_counter/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
index 3de5c660..a1eca31 100644
--- a/third_party/blink/public/mojom/use_counter/css_property_id.mojom
+++ b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
@@ -36,6 +36,7 @@
     kInternalVisitedTextEmphasisColor = 0,
     kInternalVisitedTextFillColor = 0,
     kInternalVisitedTextStrokeColor = 0,
+    kInternalFontSizeDelta = 0,
 
     // This CSSSampleId represents page load for CSS histograms. It is recorded once
     // per page visit for each CSS histogram being logged on the blink side and the
@@ -284,7 +285,7 @@
     kFlexShrink = 238,
     kFlexWrap = 239,
     kJustifyContent = 240,
-    kWebkitFontSizeDelta = 241,
+    // kWebkitFontSizeDelta = 241,
     kGridTemplateColumns = 242,
     kGridTemplateRows = 243,
     kGridColumnStart = 244,
diff --git a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
index 11abcd89..e3931ed 100644
--- a/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/activity_logger_test.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/script/classic_script.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/text/base64.h"
 #include "v8/include/v8.h"
@@ -536,6 +537,8 @@
 }
 
 TEST_F(ActivityLoggerTest, LocalDOMWindowAttribute) {
+  ScopedAllowContentInitiatedDataUrlNavigationsForTest allow_data_url(true);
+
   const char* code =
       "location.href = 'data:text/html;charset=utf-8,A';"
       "location.assign('data:text/html;charset=utf-8,B');"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index fc82b9a..5ef267c 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -1030,12 +1030,10 @@
 
   // Check that the pixel at (3, 3) is red.
   uint8_t pixel[4] = {};
-  ASSERT_TRUE(new_image_bitmap->BitmapImage()
-                  ->PaintImageForCurrentFrame()
-                  .GetSkImage()
-                  ->readPixels(SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType,
-                                                 kPremul_SkAlphaType),
-                               &pixel, 4, 3, 3));
+  ASSERT_TRUE(
+      new_image_bitmap->BitmapImage()->PaintImageForCurrentFrame().readPixels(
+          SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
+          &pixel, 4, 3, 3));
   ASSERT_THAT(pixel, testing::ElementsAre(255, 0, 0, 255));
 }
 
@@ -1072,10 +1070,9 @@
   // GPU hardware may result in small differences in lower significant byte in
   // Skia color conversion pipeline. Hence, we use a tolerance of 2 here.
   uint8_t pixel[8] = {};
-  ASSERT_TRUE(new_image_bitmap->BitmapImage()
-                  ->PaintImageForCurrentFrame()
-                  .GetSkImage()
-                  ->readPixels(info.makeWH(1, 1), &pixel, 8, 3, 3));
+  ASSERT_TRUE(
+      new_image_bitmap->BitmapImage()->PaintImageForCurrentFrame().readPixels(
+          info.makeWH(1, 1), &pixel, 8, 3, 3));
   uint8_t p3_red[8] = {0x57, 0x3B, 0x68, 0x32, 0x6E, 0x30, 0x00, 0x3C};
   bool approximate_match = true;
   uint8_t tolerance = 2;
@@ -1118,12 +1115,10 @@
 
   // Check that the pixels are opaque red and green, respectively.
   uint8_t pixels[8] = {};
-  ASSERT_TRUE(new_image_bitmap->BitmapImage()
-                  ->PaintImageForCurrentFrame()
-                  .GetSkImage()
-                  ->readPixels(SkImageInfo::Make(2, 1, kRGBA_8888_SkColorType,
-                                                 kPremul_SkAlphaType),
-                               &pixels, 8, 0, 0));
+  ASSERT_TRUE(
+      new_image_bitmap->BitmapImage()->PaintImageForCurrentFrame().readPixels(
+          SkImageInfo::Make(2, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
+          &pixels, 8, 0, 0));
   ASSERT_THAT(pixels, testing::ElementsAre(255, 0, 0, 255, 0, 255, 0, 255));
 }
 
@@ -1153,10 +1148,9 @@
       SkImageInfo::Make(1, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
                         SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
                                               SkNamedGamut::kDisplayP3));
-  ASSERT_TRUE(new_image_bitmap->BitmapImage()
-                  ->PaintImageForCurrentFrame()
-                  .GetSkImage()
-                  ->readPixels(info, &pixel, 8, 1, 0));
+  ASSERT_TRUE(
+      new_image_bitmap->BitmapImage()->PaintImageForCurrentFrame().readPixels(
+          info, &pixel, 8, 1, 0));
   // The reference values are the hex representation of red in P3 (as stored
   // in half floats by Skia).
   ASSERT_THAT(pixel, testing::ElementsAre(0x94, 0x3A, 0x3F, 0x28, 0x5F, 0x24,
diff --git a/third_party/blink/renderer/core/css/css_font_face_src_value.cc b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
index 943d9d3..e665b30c 100644
--- a/third_party/blink/renderer/core/css/css_font_face_src_value.cc
+++ b/third_party/blink/renderer/core/css/css_font_face_src_value.cc
@@ -83,7 +83,7 @@
 
 FontResource& CSSFontFaceSrcValue::Fetch(ExecutionContext* context,
                                          FontResourceClient* client) const {
-  if (!fetched_ || fetched_->GetResource()->Options().world != world_) {
+  if (!fetched_ || fetched_->GetResource()->Options().world_for_csp != world_) {
     ResourceRequest resource_request(absolute_resource_);
     resource_request.SetReferrerPolicy(
         ReferrerUtils::MojoReferrerPolicyResolveDefault(
diff --git a/third_party/blink/renderer/core/css/css_properties.json5 b/third_party/blink/renderer/core/css/css_properties.json5
index 794ea4e..0f00c3c 100644
--- a/third_party/blink/renderer/core/css/css_properties.json5
+++ b/third_party/blink/renderer/core/css/css_properties.json5
@@ -5025,8 +5025,10 @@
       affected_by_all: false,
       style_builder_template: "empty",
     },
+    // TODO(hjkim3323@gmail.com): Remove -internal-font-size-delta.
+    // fontSizeDelta execCommand does not need separate CSS property.
     {
-      name: "-webkit-font-size-delta",
+      name: "-internal-font-size-delta",
       property_methods: ["ParseSingleValue"],
       style_builder_template: "empty",
     },
diff --git a/third_party/blink/renderer/core/css/css_property_value_set.cc b/third_party/blink/renderer/core/css/css_property_value_set.cc
index 23f108b2..ee5fccdd 100644
--- a/third_party/blink/renderer/core/css/css_property_value_set.cc
+++ b/third_party/blink/renderer/core/css/css_property_value_set.cc
@@ -121,9 +121,11 @@
                             CSSPropertyID property_id) {
   DCHECK_EQ(id, static_cast<uint16_t>(property_id));
   bool result = static_cast<uint16_t>(metadata.PropertyID()) == id;
-// Only enabled properties should be part of the style.
+// Only enabled properties except kInternalFontSizeDelta should be part of the
+// style.
+// TODO(hjkim3323@gmail.com): Remove kInternalFontSizeDelta bypassing hack
 #if DCHECK_IS_ON()
-  DCHECK(!result ||
+  DCHECK(!result || property_id == CSSPropertyID::kInternalFontSizeDelta ||
          CSSProperty::Get(resolveCSSPropertyID(property_id)).IsWebExposed());
 #endif
   return result;
diff --git a/third_party/blink/renderer/core/css/parser/css_proto_converter.cc b/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
index c03d501..15a36e0 100644
--- a/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
+++ b/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
@@ -1006,7 +1006,6 @@
     "max-block-size",
     "-webkit-animation-play-state",
     "border-image-repeat",
-    "-webkit-font-size-delta",
     "scroll-padding-bottom",
     "border-right-style",
     "border-left-style",
diff --git a/third_party/blink/renderer/core/css/properties/css_property_test.cc b/third_party/blink/renderer/core/css/properties/css_property_test.cc
index 2614c27..fad2d692 100644
--- a/third_party/blink/renderer/core/css/properties/css_property_test.cc
+++ b/third_party/blink/renderer/core/css/properties/css_property_test.cc
@@ -82,6 +82,11 @@
   EXPECT_FALSE(author_set->HasProperty(CSSPropertyID::kZoom));
 }
 
+TEST_F(CSSPropertyTest, InternalFontSizeDeltaNotWebExposed) {
+  ASSERT_FALSE(
+      CSSProperty::Get(CSSPropertyID::kInternalFontSizeDelta).IsWebExposed());
+}
+
 TEST_F(CSSPropertyTest, VisitedPropertiesCanParseValues) {
   scoped_refptr<ComputedStyle> initial_style = ComputedStyle::Create();
 
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index 6edb180..aaeadfa9 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -7131,7 +7131,7 @@
                                                 allow_visited_style);
 }
 
-const CSSValue* WebkitFontSizeDelta::ParseSingleValue(
+const CSSValue* InternalFontSizeDelta::ParseSingleValue(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
     const CSSParserLocalContext&) const {
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index f7227ff..71c6e55 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -413,7 +413,7 @@
   UpdateAllLifecyclePhasesForTest();
   EXPECT_FALSE(container->GetDisplayLockContext()->IsLocked());
 
-  EXPECT_FLOAT_EQ(GetDocument().scrollingElement()->scrollTop(), 1768.5);
+  EXPECT_FLOAT_EQ(GetDocument().scrollingElement()->scrollTop(), 1768);
 }
 
 TEST_F(DisplayLockContextTest,
diff --git a/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc b/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
index 93ff98d..1c567cf5 100644
--- a/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/apply_style_command_test.cc
@@ -92,9 +92,8 @@
           "<div contenteditable>^<div></div>a<span></span>|</div>"),
       SetSelectionOptions());
 
-  auto* style =
-      MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
-  style->SetProperty(CSSPropertyID::kWebkitFontSizeDelta, "3",
+  auto* style = MakeGarbageCollected<MutableCSSPropertyValueSet>(kUASheetMode);
+  style->SetProperty(CSSPropertyID::kInternalFontSizeDelta, "3px",
                      /* important */ false,
                      GetFrame().DomWindow()->GetSecureContextMode());
   MakeGarbageCollected<ApplyStyleCommand>(
diff --git a/third_party/blink/renderer/core/editing/commands/style_commands.cc b/third_party/blink/renderer/core/editing/commands/style_commands.cc
index c0136e7..092e20b5 100644
--- a/third_party/blink/renderer/core/editing/commands/style_commands.cc
+++ b/third_party/blink/renderer/core/editing/commands/style_commands.cc
@@ -162,8 +162,10 @@
                                          Event*,
                                          EditorCommandSource source,
                                          const String& value) {
+  // TODO(hjkim3323@gmail.com): Directly set EditingStyle::font_size_delta_
+  // instead of setting it via CSS property
   return ExecuteApplyStyle(frame, source, InputEvent::InputType::kNone,
-                           CSSPropertyID::kWebkitFontSizeDelta, value);
+                           CSSPropertyID::kInternalFontSizeDelta, value);
 }
 
 bool StyleCommands::ExecuteMakeTextWritingDirectionLeftToRight(
@@ -625,7 +627,7 @@
 String StyleCommands::ValueFontSizeDelta(const EditorInternalCommand&,
                                          LocalFrame& frame,
                                          Event*) {
-  return ValueStyle(frame, CSSPropertyID::kWebkitFontSizeDelta);
+  return ValueStyle(frame, CSSPropertyID::kInternalFontSizeDelta);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/editing_style.cc b/third_party/blink/renderer/core/editing/editing_style.cc
index 274dc9f5..cb4fee97 100644
--- a/third_party/blink/renderer/core/editing/editing_style.cc
+++ b/third_party/blink/renderer/core/editing/editing_style.cc
@@ -610,13 +610,13 @@
 
   if (mutable_style_->GetPropertyCSSValue(CSSPropertyID::kFontSize)) {
     // Explicit font size overrides any delta.
-    mutable_style_->RemoveProperty(CSSPropertyID::kWebkitFontSizeDelta);
+    mutable_style_->RemoveProperty(CSSPropertyID::kInternalFontSizeDelta);
     return;
   }
 
   // Get the adjustment amount out of the style.
-  const CSSValue* value =
-      mutable_style_->GetPropertyCSSValue(CSSPropertyID::kWebkitFontSizeDelta);
+  const CSSValue* value = mutable_style_->GetPropertyCSSValue(
+      CSSPropertyID::kInternalFontSizeDelta);
   const auto* primitive_value = DynamicTo<CSSPrimitiveValue>(value);
   if (!primitive_value)
     return;
@@ -627,7 +627,7 @@
     return;
 
   font_size_delta_ = primitive_value->GetFloatValue();
-  mutable_style_->RemoveProperty(CSSPropertyID::kWebkitFontSizeDelta);
+  mutable_style_->RemoveProperty(CSSPropertyID::kInternalFontSizeDelta);
 }
 
 bool EditingStyle::IsEmpty() const {
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
index 31a9819..75eab85 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.cc
@@ -1053,7 +1053,7 @@
   builder.ReserveCapacity(kInitialCapacity);
 
   for (; !it.AtEnd(); it.Advance())
-    it.GetText().AppendTextToStringBuilder(builder);
+    it.GetTextState().AppendTextToStringBuilder(builder);
 
   if (builder.IsEmpty())
     return g_empty_string;
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.h b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
index c7cba216..18b0418 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
@@ -87,8 +87,7 @@
   // Returns the position after |char16_offset| in current text run.
   PositionTemplate<Strategy> GetPositionAfter(int char16_offset) const;
 
-  // TODO(xiaochengh): Rename to |GetTextState()|.
-  const TextIteratorTextState& GetText() const { return text_state_; }
+  const TextIteratorTextState& GetTextState() const { return text_state_; }
   int length() const { return text_state_.length(); }
   UChar CharacterAt(unsigned index) const {
     return text_state_.CharacterAt(index);
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
index 6af39c1..31325c2 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
@@ -144,7 +144,7 @@
   StringBuilder text_chunks;
   for (; !iterator.AtEnd(); iterator.Advance()) {
     text_chunks.Append('[');
-    text_chunks.Append(iterator.GetText().GetTextForTesting());
+    text_chunks.Append(iterator.GetTextState().GetTextForTesting());
     text_chunks.Append(']');
   }
   return text_chunks.ToString().Utf8();
@@ -701,14 +701,14 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 0), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.EndPositionInCurrentContainer());
 
   iter.Advance();
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 4), iter.EndPositionInCurrentContainer());
@@ -728,21 +728,21 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A)", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A)", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 3), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 5), iter.EndPositionInCurrentContainer());
 
   iter.Advance();
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ(" ", iter.GetText().GetTextForTesting());
+  EXPECT_EQ(" ", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 5), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 6), iter.EndPositionInCurrentContainer());
 
   iter.Advance();
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 7), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 10), iter.EndPositionInCurrentContainer());
@@ -762,7 +762,7 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 3), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 4), iter.EndPositionInCurrentContainer());
@@ -781,7 +781,7 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 4), iter.EndPositionInCurrentContainer());
@@ -800,14 +800,14 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 0), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.EndPositionInCurrentContainer());
 
   iter.Advance();
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 4), iter.EndPositionInCurrentContainer());
@@ -827,14 +827,14 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A)", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A)", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 3), iter.EndPositionInCurrentContainer());
 
   iter.Advance();
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 3), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 6), iter.EndPositionInCurrentContainer());
@@ -854,7 +854,7 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("A", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("A", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 2), iter.EndPositionInCurrentContainer());
@@ -873,7 +873,7 @@
   TextIterator iter(start, end);
 
   EXPECT_FALSE(iter.AtEnd());
-  EXPECT_EQ("xyz", iter.GetText().GetTextForTesting());
+  EXPECT_EQ("xyz", iter.GetTextState().GetTextForTesting());
   EXPECT_EQ(text, iter.CurrentContainer());
   EXPECT_EQ(Position(text, 1), iter.StartPositionInCurrentContainer());
   EXPECT_EQ(Position(text, 4), iter.EndPositionInCurrentContainer());
diff --git a/third_party/blink/renderer/core/editing/substring_util.mm b/third_party/blink/renderer/core/editing/substring_util.mm
index 28bca7b..e27858a 100644
--- a/third_party/blink/renderer/core/editing/substring_util.mm
+++ b/third_party/blink/renderer/core/editing/substring_util.mm
@@ -121,7 +121,7 @@
     else
       [attrs removeObjectForKey:NSBackgroundColorAttributeName];
 
-    String characters = it.GetText().GetTextForTesting();
+    String characters = it.GetTextState().GetTextForTesting();
     characters.Ensure16Bit();
     NSString* substring =
         [[[NSString alloc] initWithCharacters:characters.Characters16()
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index c870560..783d1b8 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -781,9 +781,13 @@
   DCHECK(RuntimeEnabledFeatures::BackForwardCacheEnabled());
   Vector<scoped_refptr<DOMWrapperWorld>> worlds;
   DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
+  v8::HandleScope handle_scope(V8PerIsolateData::MainThreadIsolate());
   for (const auto& world : worlds) {
+    if (!world->IsMainWorld() && !world->IsIsolatedWorld()) {
+      // Only main & isolated worlds can have ScriptStates.
+      continue;
+    }
     ScriptState* script_state = ToScriptState(this, *world);
-    ScriptState::Scope scope(script_state);
     script_state->GetContext()->SetAbortScriptExecution(
         [](v8::Isolate* isolate, v8::Local<v8::Context> context) {
           ScriptState* script_state = ScriptState::From(context);
@@ -800,9 +804,13 @@
   DCHECK(RuntimeEnabledFeatures::BackForwardCacheEnabled());
   Vector<scoped_refptr<DOMWrapperWorld>> worlds;
   DOMWrapperWorld::AllWorldsInCurrentThread(worlds);
+  v8::HandleScope handle_scope(V8PerIsolateData::MainThreadIsolate());
   for (const auto& world : worlds) {
+    if (!world->IsMainWorld() && !world->IsIsolatedWorld()) {
+      // Only main & isolated worlds can have ScriptStates.
+      continue;
+    }
     ScriptState* script_state = ToScriptState(this, *world);
-    ScriptState::Scope scope(script_state);
     script_state->GetContext()->SetAbortScriptExecution(nullptr);
   }
 }
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 2779a73..08a9129 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -48,10 +48,6 @@
 constexpr const char* kImageBitmapOptionResizeQualityHigh = "high";
 constexpr const char* kImageBitmapOptionResizeQualityMedium = "medium";
 constexpr const char* kImageBitmapOptionResizeQualityPixelated = "pixelated";
-constexpr const char* kPreserveImageBitmapColorSpaceConversion = "preserve";
-constexpr const char* kSRGBImageBitmapColorSpaceConversion = "srgb";
-constexpr const char* kP3ImageBitmapColorSpaceConversion = "p3";
-constexpr const char* kRec2020ImageBitmapColorSpaceConversion = "rec2020";
 
 namespace {
 
@@ -96,27 +92,12 @@
 
   parsed_options.has_color_space_conversion =
       (options->colorSpaceConversion() != kImageBitmapOptionNone);
-  parsed_options.preserve_source_color_space =
-      (options->colorSpaceConversion() ==
-       kPreserveImageBitmapColorSpaceConversion);
   parsed_options.color_params.SetCanvasColorSpace(CanvasColorSpace::kSRGB);
-  if (options->colorSpaceConversion() != kSRGBImageBitmapColorSpaceConversion &&
-      options->colorSpaceConversion() !=
-          kPreserveImageBitmapColorSpaceConversion &&
-      options->colorSpaceConversion() != kImageBitmapOptionNone &&
+  if (options->colorSpaceConversion() != kImageBitmapOptionNone &&
       options->colorSpaceConversion() != kImageBitmapOptionDefault) {
-    parsed_options.color_params.SetCanvasPixelFormat(CanvasPixelFormat::kF16);
-    if (options->colorSpaceConversion() == kP3ImageBitmapColorSpaceConversion) {
-      parsed_options.color_params.SetCanvasColorSpace(CanvasColorSpace::kP3);
-    } else if (options->colorSpaceConversion() ==
-               kRec2020ImageBitmapColorSpaceConversion) {
-      parsed_options.color_params.SetCanvasColorSpace(
-          CanvasColorSpace::kRec2020);
-    } else {
-      NOTREACHED()
-          << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
-          << IDLEnumAsString(options->colorSpaceConversion());
-    }
+    NOTREACHED()
+        << "Invalid ImageBitmap creation attribute colorSpaceConversion: "
+        << IDLEnumAsString(options->colorSpaceConversion());
   }
 
   int source_width = source_size.Width();
@@ -456,15 +437,7 @@
   if (src_image_info.isEmpty())
     return nullptr;
 
-  // If we should preserve color precision, don't lose it in color space
-  // conversion.
-  if (options.pixel_format == kImageBitmapPixelFormat_Default &&
-      (src_image_info.colorType() == kRGBA_F16_SkColorType ||
-       (src_image_info.colorSpace() &&
-        src_image_info.colorSpace()->gammaIsLinear()) ||
-       (color_space && color_space->gammaIsLinear()))) {
-    color_type = kRGBA_F16_SkColorType;
-  }
+  // This will always convert to 8-bit sRGB.
   return image->ConvertToColorSpace(color_space, color_type);
 }
 
@@ -561,8 +534,7 @@
   }
 
   // color convert if needed
-  if (parsed_options.has_color_space_conversion &&
-      !parsed_options.preserve_source_color_space) {
+  if (parsed_options.has_color_space_conversion) {
     result = ApplyColorSpaceConversion(std::move(result), parsed_options);
     if (!result)
       return nullptr;
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
index e77c837..ebe1676d 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.h
@@ -126,7 +126,6 @@
     bool premultiply_alpha = true;
     bool should_scale_input = false;
     bool has_color_space_conversion = false;
-    bool preserve_source_color_space = false;
     bool source_is_unpremul = false;
     unsigned resize_width = 0;
     unsigned resize_height = 0;
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index de2b9ba..c8a7697 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -308,69 +308,6 @@
   }
 }
 
-TEST_F(ImageBitmapTest, ImageBitmapPixelFormat) {
-  SkImageInfo info = SkImageInfo::MakeS32(10, 10, kPremul_SkAlphaType);
-  sk_sp<SkSurface> surface(SkSurface::MakeRaster(info));
-  sk_sp<SkImage> sk_image = surface->makeImageSnapshot();
-  scoped_refptr<StaticBitmapImage> bitmap_image =
-      UnacceleratedStaticBitmapImage::Create(sk_image);
-
-  // source: uint8, bitmap pixel format: default
-  ImageBitmapOptions* options = ImageBitmapOptions::Create();
-  auto* image_bitmap = MakeGarbageCollected<ImageBitmap>(
-      bitmap_image, bitmap_image->Rect(), options);
-
-  ASSERT_TRUE(image_bitmap);
-  sk_sp<SkImage> sk_image_internal =
-      image_bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSwSkImage();
-  ASSERT_EQ(kN32_SkColorType, sk_image_internal->colorType());
-
-  // source: uint8, bitmap pixel format: uint8
-  options->setImagePixelFormat("uint8");
-  auto* image_bitmap_8888 = MakeGarbageCollected<ImageBitmap>(
-      bitmap_image, bitmap_image->Rect(), options);
-  ASSERT_TRUE(image_bitmap_8888);
-  sk_sp<SkImage> sk_image_internal_8888 = image_bitmap_8888->BitmapImage()
-                                              ->PaintImageForCurrentFrame()
-                                              .GetSwSkImage();
-  ASSERT_EQ(kN32_SkColorType, sk_image_internal_8888->colorType());
-
-  // Since there is no conversion from uint8 to default for image bitmap pixel
-  // format option, we expect the two image bitmaps to refer to the same
-  // internal SkImage back storage.
-  ASSERT_EQ(sk_image_internal, sk_image_internal_8888);
-
-  sk_sp<SkColorSpace> p3_color_space = SkColorSpace::MakeRGB(
-      SkNamedTransferFn::kLinear, SkNamedGamut::kDisplayP3);
-  SkImageInfo info_f16 = SkImageInfo::Make(10, 10, kRGBA_F16_SkColorType,
-                                           kPremul_SkAlphaType, p3_color_space);
-  sk_sp<SkSurface> surface_f16(SkSurface::MakeRaster(info_f16));
-  sk_sp<SkImage> sk_image_f16 = surface_f16->makeImageSnapshot();
-  scoped_refptr<StaticBitmapImage> bitmap_image_f16 =
-      UnacceleratedStaticBitmapImage::Create(sk_image_f16);
-
-  // source: f16, bitmap pixel format: default
-  ImageBitmapOptions* options_f16 = ImageBitmapOptions::Create();
-  auto* image_bitmap_f16 = MakeGarbageCollected<ImageBitmap>(
-      bitmap_image_f16, bitmap_image_f16->Rect(), options_f16);
-  ASSERT_TRUE(image_bitmap_f16);
-  sk_sp<SkImage> sk_image_internal_f16 = image_bitmap_f16->BitmapImage()
-                                             ->PaintImageForCurrentFrame()
-                                             .GetSwSkImage();
-  ASSERT_EQ(kRGBA_F16_SkColorType, sk_image_internal_f16->colorType());
-
-  // source: f16, bitmap pixel format: uint8
-  options_f16->setImagePixelFormat("uint8");
-  auto* image_bitmap_f16_8888 = MakeGarbageCollected<ImageBitmap>(
-      bitmap_image_f16, bitmap_image_f16->Rect(), options_f16);
-  ASSERT_TRUE(image_bitmap_f16_8888);
-  sk_sp<SkImage> sk_image_internal_f16_8888 =
-      image_bitmap_f16_8888->BitmapImage()
-          ->PaintImageForCurrentFrame()
-          .GetSwSkImage();
-  ASSERT_EQ(kN32_SkColorType, sk_image_internal_f16_8888->colorType());
-}
-
 // This test is failing on asan-clang-phone because memory allocation is
 // declined. See <http://crbug.com/782286>.
 // See <http://crbug.com/1090252>, test is flaky in fuchsia.
diff --git a/third_party/blink/renderer/core/inspector/BUILD.gn b/third_party/blink/renderer/core/inspector/BUILD.gn
index 6ebb46147..e7ed542 100644
--- a/third_party/blink/renderer/core/inspector/BUILD.gn
+++ b/third_party/blink/renderer/core/inspector/BUILD.gn
@@ -107,6 +107,8 @@
     "main_thread_debugger.h",
     "network_resources_data.cc",
     "network_resources_data.h",
+    "request_debug_header_scope.cc",
+    "request_debug_header_scope.h",
     "resolve_node.cc",
     "resolve_node.h",
     "thread_debugger.cc",
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
index 87fa475..20e71fd 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/core/inspector/identifiers_factory.h"
 #include "third_party/blink/renderer/core/inspector/inspected_frames.h"
 #include "third_party/blink/renderer/core/inspector/network_resources_data.h"
+#include "third_party/blink/renderer/core/inspector/request_debug_header_scope.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/frame_loader.h"
 #include "third_party/blink/renderer/core/loader/mixed_content_checker.h"
@@ -1009,6 +1010,22 @@
   }
   if (bypass_service_worker_.Get())
     request.SetSkipServiceWorker(true);
+
+  if (debug_header_enabled_.Get() &&
+      request.HttpHeaderField(RequestDebugHeaderScope::kHeaderName).IsNull()) {
+    ExecutionContext* context = nullptr;
+    if (worker_global_scope_) {
+      context = worker_global_scope_.Get();
+    } else if (loader && loader->GetFrame()) {
+      context = loader->GetFrame()->GetDocument()->ExecutingWindow();
+    }
+    String header =
+        RequestDebugHeaderScope::CaptureHeaderForCurrentLocation(context);
+    if (!header.IsNull()) {
+      request.SetHttpHeaderField(RequestDebugHeaderScope::kHeaderName,
+                                 AtomicString(header));
+    }
+  }
 }
 
 void InspectorNetworkAgent::WillSendRequest(
@@ -1522,6 +1539,13 @@
   return Response::Success();
 }
 
+Response InspectorNetworkAgent::setAttachDebugHeader(bool enabled) {
+  if (enabled && !enabled_.Get())
+    return Response::InvalidParams("Domain must be enabled");
+  debug_header_enabled_.Set(enabled);
+  return Response::Success();
+}
+
 bool InspectorNetworkAgent::CanGetResponseBodyBlob(const String& request_id) {
   NetworkResourcesData::ResourceData const* resource_data =
       resources_data_->Data(request_id);
@@ -1857,6 +1881,7 @@
       bypass_service_worker_(&agent_state_, /*default_value=*/false),
       blocked_urls_(&agent_state_, /*default_value=*/false),
       extra_request_headers_(&agent_state_, /*default_value=*/WTF::String()),
+      debug_header_enabled_(&agent_state_, /*default_value=*/false),
       total_buffer_size_(&agent_state_,
                          /*default_value=*/kDefaultTotalBufferSize),
       resource_buffer_size_(&agent_state_,
diff --git a/third_party/blink/renderer/core/inspector/inspector_network_agent.h b/third_party/blink/renderer/core/inspector/inspector_network_agent.h
index 23a2962..b2b48ef 100644
--- a/third_party/blink/renderer/core/inspector/inspector_network_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_network_agent.h
@@ -204,6 +204,7 @@
   protocol::Response disable() override;
   protocol::Response setExtraHTTPHeaders(
       std::unique_ptr<protocol::Network::Headers>) override;
+  protocol::Response setAttachDebugHeader(bool enabled) override;
   void getResponseBody(const String& request_id,
                        std::unique_ptr<GetResponseBodyCallback>) override;
   protocol::Response searchInResponseBody(
@@ -293,6 +294,7 @@
   InspectorAgentState::Boolean bypass_service_worker_;
   InspectorAgentState::BooleanMap blocked_urls_;
   InspectorAgentState::StringMap extra_request_headers_;
+  InspectorAgentState::Boolean debug_header_enabled_;
   InspectorAgentState::Integer total_buffer_size_;
   InspectorAgentState::Integer resource_buffer_size_;
   InspectorAgentState::Integer max_post_data_size_;
diff --git a/third_party/blink/renderer/core/inspector/request_debug_header_scope.cc b/third_party/blink/renderer/core/inspector/request_debug_header_scope.cc
new file mode 100644
index 0000000..7860fa4
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/request_debug_header_scope.cc
@@ -0,0 +1,57 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/request_debug_header_scope.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
+#include "third_party/blink/renderer/core/inspector/protocol/Protocol.h"
+#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
+#include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
+
+namespace blink {
+
+// static
+const char RequestDebugHeaderScope::kHeaderName[] = "X-Debug-Stack-Trace-Id";
+
+// static
+String RequestDebugHeaderScope::CaptureHeaderForCurrentLocation(
+    ExecutionContext* context) {
+  ThreadDebugger* debugger = nullptr;
+  if (auto* scope = DynamicTo<WorkerGlobalScope>(context))
+    debugger = WorkerThreadDebugger::From(scope->GetThread()->GetIsolate());
+  else if (LocalDOMWindow* dom_window = DynamicTo<LocalDOMWindow>(context))
+    debugger = MainThreadDebugger::Instance();
+  if (!debugger)
+    return String();
+  auto stack = debugger->StoreCurrentStackTrace("network request").ToString();
+  return stack ? ToCoreString(std::move(stack)) : String();
+}
+
+RequestDebugHeaderScope::RequestDebugHeaderScope(ExecutionContext* context,
+                                                 const String& header) {
+  if (header.IsEmpty())
+    return;
+  stack_trace_id_ =
+      v8_inspector::V8StackTraceId(ToV8InspectorStringView(header));
+  if (stack_trace_id_.IsInvalid())
+    return;
+  if (auto* scope = DynamicTo<WorkerGlobalScope>(context))
+    debugger_ = WorkerThreadDebugger::From(scope->GetThread()->GetIsolate());
+  else if (auto* window = DynamicTo<LocalDOMWindow>(context))
+    debugger_ = MainThreadDebugger::Instance();
+  if (debugger_)
+    debugger_->ExternalAsyncTaskStarted(stack_trace_id_);
+}
+
+RequestDebugHeaderScope::~RequestDebugHeaderScope() {
+  if (debugger_)
+    debugger_->ExternalAsyncTaskFinished(stack_trace_id_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/request_debug_header_scope.h b/third_party/blink/renderer/core/inspector/request_debug_header_scope.h
new file mode 100644
index 0000000..275bdfc
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/request_debug_header_scope.h
@@ -0,0 +1,36 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_REQUEST_DEBUG_HEADER_SCOPE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_REQUEST_DEBUG_HEADER_SCOPE_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "v8/include/v8-inspector.h"
+
+namespace blink {
+
+class ExecutionContext;
+class ThreadDebugger;
+
+class CORE_EXPORT RequestDebugHeaderScope {
+  STACK_ALLOCATED();
+
+ public:
+  static const char kHeaderName[];
+
+  static String CaptureHeaderForCurrentLocation(ExecutionContext*);
+
+  RequestDebugHeaderScope(ExecutionContext*, const String& header);
+  ~RequestDebugHeaderScope();
+
+ private:
+  ThreadDebugger* debugger_ = nullptr;
+  v8_inspector::V8StackTraceId stack_trace_id_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_REQUEST_DEBUG_HEADER_SCOPE_H_
diff --git a/third_party/blink/renderer/core/layout/layout_block_flow.cc b/third_party/blink/renderer/core/layout/layout_block_flow.cc
index e1a95687..25c662bf 100644
--- a/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -4331,7 +4331,7 @@
 bool LayoutBlockFlow::CreatesNewFormattingContext() const {
   if (IsInline() || IsFloatingOrOutOfFlowPositioned() ||
       HasNonVisibleOverflow() || IsFlexItemIncludingDeprecatedAndNG() ||
-      IsCustomItem() || IsDocumentElement() || IsGridItem() ||
+      IsCustomItem() || IsDocumentElement() || IsGridItemIncludingNG() ||
       IsWritingModeRoot() || IsMathItem() ||
       StyleRef().Display() == EDisplay::kFlowRoot ||
       ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() ||
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 5e97da7..063970b2 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1403,6 +1403,10 @@
     return !IsInline() && !IsOutOfFlowPositioned() && Parent();
   }
 
+  bool IsGridItemIncludingNG() const {
+    return IsGridItem() || (Parent() && Parent()->IsLayoutNGGrid());
+  }
+
   bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
 
   bool IsMathItem() const { return Parent() && Parent()->IsMathML(); }
diff --git a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
index 80a2f0e..582b975 100644
--- a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
@@ -169,18 +169,6 @@
 LayoutDeprecatedFlexibleBox::LayoutDeprecatedFlexibleBox(Element* element)
     : LayoutBlock(element) {
   DCHECK(!ChildrenInline());
-  if (!IsAnonymous()) {
-    const KURL& url = GetDocument().Url();
-    if (url.ProtocolIs("chrome")) {
-      UseCounter::Count(GetDocument(), WebFeature::kDeprecatedFlexboxChrome);
-    } else if (url.ProtocolIs("chrome-extension")) {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kDeprecatedFlexboxChromeExtension);
-    } else {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kDeprecatedFlexboxWebContent);
-    }
-  }
 }
 
 LayoutDeprecatedFlexibleBox::~LayoutDeprecatedFlexibleBox() = default;
@@ -199,28 +187,6 @@
   return margin;
 }
 
-static LayoutUnit HeightForChild(LayoutBox* child) {
-  if (child->HasOverrideLogicalHeight())
-    return child->OverrideLogicalHeight();
-  return child->LogicalHeight();
-}
-
-static LayoutUnit ContentHeightForChild(LayoutBox* child) {
-  // TODO(rego): Shouldn't we subtract the scrollbar height too?
-  return (HeightForChild(child) - child->BorderAndPaddingLogicalHeight())
-      .ClampNegativeToZero();
-}
-
-void LayoutDeprecatedFlexibleBox::StyleWillChange(
-    StyleDifference diff,
-    const ComputedStyle& new_style) {
-  const ComputedStyle* old_style = Style();
-  if (old_style && old_style->HasLineClamp() && !new_style.HasLineClamp())
-    ClearLineClamp();
-
-  LayoutBlock::StyleWillChange(diff, new_style);
-}
-
 MinMaxSizes LayoutDeprecatedFlexibleBox::ComputeIntrinsicLogicalWidths() const {
   MinMaxSizes sizes;
   for (LayoutBox* child = FirstChildBox(); child;
@@ -242,27 +208,9 @@
 void LayoutDeprecatedFlexibleBox::UpdateBlockLayout(bool relayout_children) {
   DCHECK(NeedsLayout());
   DCHECK_EQ(StyleRef().BoxOrient(), EBoxOrient::kVertical);
-
+  DCHECK(StyleRef().HasLineClamp());
   UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayout);
 
-  if (StyleRef().BoxDirection() !=
-      ComputedStyleInitialValues::InitialBoxDirection())
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxDirectionNotInitial);
-
-  if (!FirstChildBox()) {
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxNoChildren);
-  } else if (!FirstChildBox()->NextSiblingBox()) {
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxOneChild);
-
-    auto* first_child_block_flow = DynamicTo<LayoutBlockFlow>(FirstChildBox());
-    if (first_child_block_flow && first_child_block_flow->ChildrenInline()) {
-      UseCounter::Count(GetDocument(),
-                        WebFeature::kWebkitBoxOneChildIsLayoutBlockFlowInline);
-    }
-  } else {
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxManyChildren);
-  }
-
   if (!relayout_children && SimplifiedLayout())
     return;
 
@@ -282,7 +230,6 @@
 
     SetHeight(LayoutUnit());
 
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayoutVertical);
     LayoutVerticalBox(relayout_children);
 
     LayoutUnit old_client_after_edge = ClientLogicalBottom();
@@ -301,257 +248,95 @@
   ClearNeedsLayout();
 }
 
-// The first walk over our kids is to find out if we have any flexible children.
-static void GatherFlexChildrenInfo(LayoutBox* first_child_box,
-                                   Document& document,
-                                   bool relayout_children,
-                                   bool& have_flex) {
-  for (LayoutBox* child = first_child_box; child;
-       child = child->NextSiblingBox()) {
-    if (child->StyleRef().BoxFlex() !=
-        ComputedStyleInitialValues::InitialBoxFlex())
-      UseCounter::Count(document, WebFeature::kWebkitBoxChildFlexNotInitial);
-
-    // Check to see if this child flexes.
-    if (!child->IsOutOfFlowPositioned() && child->StyleRef().BoxFlex() > 0.0f) {
-      // We always have to lay out flexible objects again, since the flex
-      // distribution
-      // may have changed, and we need to reallocate space.
-      child->ClearOverrideSize();
-      if (!relayout_children)
-        child->SetChildNeedsLayout(kMarkOnlyThis);
-      have_flex = true;
-    }
-  }
-}
-
 void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
-  LayoutUnit y_pos = BorderTop() + PaddingTop();
   LayoutUnit to_add =
       BorderBottom() + PaddingBottom() + HorizontalScrollbarHeight();
-  bool height_specified = false;
-  bool paginated = View()->GetLayoutState()->IsPaginated();
-  LayoutUnit old_height;
-
-  LayoutUnit remaining_space;
-
-  bool have_flex = false, flexing_children = false;
-  GatherFlexChildrenInfo(FirstChildBox(), GetDocument(), relayout_children,
-                         have_flex);
 
   // We confine the line clamp ugliness to vertical flexible boxes (thus keeping
-  // it out of
-  // mainstream block layout); this is not really part of the XUL box model.
-  if (StyleRef().HasLineClamp())
-    ApplyLineClamp(relayout_children);
+  // it out of mainstream block layout); this is not really part of the XUL box
+  // model.
+  ApplyLineClamp(relayout_children);
 
   PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
 
-  // We do 2 passes.  The first pass is simply to lay everyone out at
-  // their preferred widths.  The second pass handles flexing the children.
-  // Our first pass is done without flexing.  We simply lay the children
-  // out within the box.
-  do {
-    SetHeight(BorderTop() + PaddingTop());
-    LayoutUnit min_height = Size().Height() + to_add;
+  SetHeight(BorderTop() + PaddingTop());
+  LayoutUnit min_height = Size().Height() + to_add;
 
-    for (LayoutBox* child = FirstChildBox(); child;
-         child = child->NextSiblingBox()) {
-      if (child->IsOutOfFlowPositioned()) {
-        child->ContainingBlock()->InsertPositionedObject(child);
-        PaintLayer* child_layer = child->Layer();
-        child_layer->SetStaticInlinePosition(BorderStart() + PaddingStart());
-        if (child_layer->StaticBlockPosition() != Size().Height()) {
-          child_layer->SetStaticBlockPosition(Size().Height());
-          if (child->StyleRef().HasStaticBlockPosition(
-                  StyleRef().IsHorizontalWritingMode()))
-            child->SetChildNeedsLayout(kMarkOnlyThis);
-        }
-        continue;
+  for (LayoutBox* child = FirstChildBox(); child;
+       child = child->NextSiblingBox()) {
+    if (child->IsOutOfFlowPositioned()) {
+      child->ContainingBlock()->InsertPositionedObject(child);
+      PaintLayer* child_layer = child->Layer();
+      child_layer->SetStaticInlinePosition(BorderStart() + PaddingStart());
+      if (child_layer->StaticBlockPosition() != Size().Height()) {
+        child_layer->SetStaticBlockPosition(Size().Height());
+        if (child->StyleRef().HasStaticBlockPosition(
+                StyleRef().IsHorizontalWritingMode()))
+          child->SetChildNeedsLayout(kMarkOnlyThis);
       }
-
-      SubtreeLayoutScope layout_scope(*child);
-      if (!StyleRef().HasLineClamp() &&
-          (relayout_children ||
-           (child->IsAtomicInlineLevel() &&
-            (child->StyleRef().Width().IsPercentOrCalc() ||
-             child->StyleRef().Height().IsPercentOrCalc()))))
-        layout_scope.SetChildNeedsLayout(child);
-
-      // Compute the child's vertical margins.
-      child->ComputeAndSetBlockDirectionMargins(this);
-
-      // Add in the child's marginTop to our height.
-      SetHeight(Size().Height() + child->MarginTop());
-
-      if (!child->NeedsLayout())
-        MarkChildForPaginationRelayoutIfNeeded(*child, layout_scope);
-
-      // Now do a layout.
-      child->LayoutIfNeeded();
-
-      // Place the child.
-      LayoutUnit child_x = BorderLeft() + PaddingLeft();
-      if (StyleRef().IsLeftToRightDirection()) {
-        child_x += child->MarginLeft();
-      } else {
-        child_x +=
-            ContentWidth() - child->MarginRight() - child->Size().Width();
-      }
-      PlaceChild(child, LayoutPoint(child_x, Size().Height()));
-      SetHeight(Size().Height() + child->Size().Height() +
-                child->MarginBottom());
-
-      if (paginated)
-        UpdateFragmentationInfoForChild(*child);
+      continue;
     }
 
-    y_pos = Size().Height();
+    // Compute the child's vertical margins.
+    child->ComputeAndSetBlockDirectionMargins(this);
 
-    if (!FirstChildBox() && HasLineIfEmpty()) {
-      SetHeight(Size().Height() +
-                LineHeight(true,
-                           StyleRef().IsHorizontalWritingMode()
-                               ? kHorizontalLine
-                               : kVerticalLine,
-                           kPositionOfInteriorLineBoxes));
+    // Add in the child's marginTop to our height.
+    SetHeight(Size().Height() + child->MarginTop());
+
+    SubtreeLayoutScope layout_scope(*child);
+    if (!child->NeedsLayout())
+      MarkChildForPaginationRelayoutIfNeeded(*child, layout_scope);
+
+    // Now do a layout.
+    child->LayoutIfNeeded();
+
+    // Place the child.
+    LayoutUnit child_x = BorderLeft() + PaddingLeft();
+    if (StyleRef().IsLeftToRightDirection()) {
+      child_x += child->MarginLeft();
+    } else {
+      child_x += ContentWidth() - child->MarginRight() - child->Size().Width();
     }
+    // TODO(crbug.com/370010): Investigate if this can be removed based on
+    // other flags.
+    child->SetShouldCheckForPaintInvalidation();
+    child->SetLocation(LayoutPoint(child_x, Size().Height()));
 
-    SetHeight(Size().Height() + to_add);
+    SetHeight(Size().Height() + child->Size().Height() + child->MarginBottom());
 
-    // Negative margins can cause our height to shrink below our minimal height
-    // (border/padding).  If this happens, ensure that the computed height is
-    // increased to the minimal height.
-    if (Size().Height() < min_height)
-      SetHeight(min_height);
+    if (View()->GetLayoutState()->IsPaginated())
+      UpdateFragmentationInfoForChild(*child);
+  }
 
-    // Now we have to calc our height, so we know how much space we have
-    // remaining.
-    old_height = Size().Height();
-    UpdateLogicalHeight();
-    if (old_height != Size().Height())
-      height_specified = true;
+  if (!FirstChildBox() && HasLineIfEmpty()) {
+    SetHeight(Size().Height() + LineHeight(true,
+                                           StyleRef().IsHorizontalWritingMode()
+                                               ? kHorizontalLine
+                                               : kVerticalLine,
+                                           kPositionOfInteriorLineBoxes));
+  }
 
-    remaining_space = Size().Height() - BorderBottom() - PaddingBottom() -
-                      HorizontalScrollbarHeight() - y_pos;
+  SetHeight(Size().Height() + to_add);
 
-    if (flexing_children) {
-      have_flex = false;  // We're done.
-    } else if (have_flex) {
-      // We have some flexible objects.  See if we need to grow/shrink them at
-      // all.
-      if (!remaining_space)
-        break;
+  // Negative margins can cause our height to shrink below our minimal height
+  // (border/padding).  If this happens, ensure that the computed height is
+  // increased to the minimal height.
+  if (Size().Height() < min_height)
+    SetHeight(min_height);
 
-      // Allocate the remaining space among the flexible objects.
-      bool expanding = remaining_space > 0;
-      do {
-        // Flexing consists of multiple passes, since we have to change
-        // ratios every time an object hits its max/min-width For a given
-        // pass, we always start off by computing the totalFlex of all
-        // objects that can grow/shrink at all, and computing the allowed
-        // growth before an object hits its min/max width (and thus forces a
-        // totalFlex recomputation).
-        LayoutUnit remaining_space_at_beginning = remaining_space;
-        float total_flex = 0.0f;
-        for (LayoutBox* child = FirstChildBox(); child;
-             child = child->NextSiblingBox()) {
-          if (AllowedChildFlex(child, expanding))
-            total_flex += child->StyleRef().BoxFlex();
-        }
-        LayoutUnit space_available_this_pass = remaining_space;
-        for (LayoutBox* child = FirstChildBox(); child;
-             child = child->NextSiblingBox()) {
-          LayoutUnit allowed_flex = AllowedChildFlex(child, expanding);
-          if (allowed_flex) {
-            LayoutUnit projected_flex =
-                (allowed_flex == LayoutUnit::Max())
-                    ? allowed_flex
-                    : static_cast<LayoutUnit>(
-                          allowed_flex *
-                          (total_flex / child->StyleRef().BoxFlex()));
-            space_available_this_pass =
-                expanding ? std::min(space_available_this_pass, projected_flex)
-                          : std::max(space_available_this_pass, projected_flex);
-          }
-        }
-
-        // If we can't grow/shrink anymore, break.
-        if (!space_available_this_pass || total_flex == 0.0f)
-          break;
-
-        // Now distribute the space to objects.
-        for (LayoutBox* child = FirstChildBox();
-             child && space_available_this_pass && total_flex;
-             child = child->NextSiblingBox()) {
-          if (AllowedChildFlex(child, expanding)) {
-            LayoutUnit space_add = static_cast<LayoutUnit>(
-                space_available_this_pass *
-                (child->StyleRef().BoxFlex() / total_flex));
-            if (space_add) {
-              child->SetOverrideLogicalHeight(HeightForChild(child) +
-                                              space_add);
-              flexing_children = true;
-              relayout_children = true;
-            }
-
-            space_available_this_pass -= space_add;
-            remaining_space -= space_add;
-
-            total_flex -= child->StyleRef().BoxFlex();
-          }
-        }
-        if (remaining_space == remaining_space_at_beginning) {
-          // This is not advancing, avoid getting stuck by distributing the
-          // remaining pixels.
-          LayoutUnit space_add = LayoutUnit(remaining_space > 0 ? 1 : -1);
-          for (LayoutBox* child = FirstChildBox(); child && remaining_space;
-               child = child->NextSiblingBox()) {
-            if (AllowedChildFlex(child, expanding)) {
-              child->SetOverrideLogicalHeight(HeightForChild(child) +
-                                              space_add);
-              flexing_children = true;
-              relayout_children = true;
-              remaining_space -= space_add;
-            }
-          }
-        }
-      } while (AbsoluteValue(remaining_space) >= 1);
-
-      // We didn't find any children that could grow.
-      if (have_flex && !flexing_children)
-        have_flex = false;
-    }
-  } while (have_flex);
+  // Now we have to calc our height, so we know how much space we have
+  // remaining.
+  LayoutUnit old_height = Size().Height();
+  UpdateLogicalHeight();
 
   // So that the computeLogicalHeight in layoutBlock() knows to relayout
   // positioned objects because of a height change, we revert our height back
   // to the intrinsic height before returning.
-  if (height_specified)
+  if (old_height != Size().Height())
     SetHeight(old_height);
 }
 
 void LayoutDeprecatedFlexibleBox::ApplyLineClamp(bool relayout_children) {
-  UseCounter::Count(GetDocument(), WebFeature::kLineClamp);
-  UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLineClamp);
-
-  LayoutBox* child = FirstChildBox();
-  if (!child) {
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLineClampNoChildren);
-  } else if (!child->NextSiblingBox()) {
-    UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLineClampOneChild);
-
-    auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
-    if (child_block_flow && child_block_flow->ChildrenInline()) {
-      UseCounter::Count(
-          GetDocument(),
-          WebFeature::kWebkitBoxLineClampOneChildIsLayoutBlockFlowInline);
-    }
-  } else {
-    UseCounter::Count(GetDocument(),
-                      WebFeature::kWebkitBoxLineClampManyChildren);
-  }
-
   int max_line_count = 0;
   for (LayoutBox* child = FirstChildBox(); child;
        child = child->NextSiblingBox()) {
@@ -651,9 +436,6 @@
             LayoutUnit(total_width)))
       continue;
 
-    UseCounter::Count(GetDocument(),
-                      WebFeature::kWebkitBoxLineClampDoesSomething);
-
     // Let the truncation code kick in.
     // FIXME: the text alignment should be recomputed after the width changes
     // due to truncation.
@@ -668,63 +450,4 @@
   }
 }
 
-void LayoutDeprecatedFlexibleBox::ClearLineClamp() {
-  for (LayoutBox* child = FirstChildBox(); child;
-       child = child->NextSiblingBox()) {
-    if (child->IsOutOfFlowPositioned())
-      continue;
-
-    child->ClearOverrideSize();
-    if ((child->IsAtomicInlineLevel() &&
-         (child->StyleRef().Width().IsPercentOrCalc() ||
-          child->StyleRef().Height().IsPercentOrCalc())) ||
-        (child->StyleRef().Height().IsAuto() && child->IsLayoutBlock())) {
-      child->SetChildNeedsLayout();
-
-      auto* child_block_flow = DynamicTo<LayoutBlockFlow>(child);
-      if (child_block_flow) {
-        child_block_flow->MarkPositionedObjectsForLayout();
-        ClearTruncation(child_block_flow);
-      }
-    }
-  }
-}
-
-void LayoutDeprecatedFlexibleBox::PlaceChild(LayoutBox* child,
-                                             const LayoutPoint& location) {
-  // FIXME Investigate if this can be removed based on other flags.
-  // crbug.com/370010
-  child->SetShouldCheckForPaintInvalidation();
-
-  // Place the child.
-  child->SetLocation(location);
-}
-
-LayoutUnit LayoutDeprecatedFlexibleBox::AllowedChildFlex(LayoutBox* child,
-                                                         bool expanding) {
-  if (child->IsOutOfFlowPositioned() || child->StyleRef().BoxFlex() == 0.0f)
-    return LayoutUnit();
-
-  if (expanding) {
-    // FIXME: For now just handle fixed values.
-    LayoutUnit max_height = LayoutUnit::Max();
-    LayoutUnit height = ContentHeightForChild(child);
-    if (child->StyleRef().MaxHeight().IsFixed())
-      max_height = LayoutUnit(child->StyleRef().MaxHeight().Value());
-    if (max_height == LayoutUnit::Max())
-      return max_height;
-    return (max_height - height).ClampNegativeToZero();
-  }
-
-  // FIXME: For now just handle fixed values.
-  const Length& min_height_length = child->StyleRef().MinHeight();
-  if (min_height_length.IsFixed() || min_height_length.IsAuto()) {
-    LayoutUnit min_height(min_height_length.Value());
-    LayoutUnit height = ContentHeightForChild(child);
-    LayoutUnit allowed_shrinkage = (min_height - height).ClampPositiveToZero();
-    return allowed_shrinkage;
-  }
-  return LayoutUnit();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
index 6499c59..78bf29f3 100644
--- a/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
+++ b/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
@@ -36,24 +36,16 @@
 
   const char* GetName() const override { return "LayoutDeprecatedFlexibleBox"; }
 
-  void StyleWillChange(StyleDifference,
-                       const ComputedStyle& new_style) override;
-
   void UpdateBlockLayout(bool relayout_children) override;
   void LayoutVerticalBox(bool relayout_children);
 
   bool IsDeprecatedFlexibleBox() const override { return true; }
   bool IsFlexibleBoxIncludingDeprecatedAndNG() const override { return true; }
 
-  void PlaceChild(LayoutBox* child, const LayoutPoint& location);
-
  private:
   MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
 
-  LayoutUnit AllowedChildFlex(LayoutBox* child, bool expanding);
-
   void ApplyLineClamp(bool relayout_children);
-  void ClearLineClamp();
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index c09e6676..ea874327 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -677,6 +677,7 @@
   bool IsLayoutNGFlexibleBox() const {
     return IsOfType(kLayoutObjectNGFlexibleBox);
   }
+  bool IsLayoutNGGrid() const { return IsOfType(kLayoutObjectNGGrid); }
   bool IsLayoutNGMixin() const { return IsOfType(kLayoutObjectNGMixin); }
   bool IsLayoutNGListItem() const { return IsOfType(kLayoutObjectNGListItem); }
   bool IsLayoutNGInsideListMarker() const {
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator_test.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator_test.cc
index d5468ce..65e1d05 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator_test.cc
@@ -11,7 +11,14 @@
 
 TEST_F(NGLayoutTest, TestNGGridChildIterator) {
   SetBodyInnerHTML(R"HTML(
-    <div id="parent" style="display: grid">
+    <style>
+    #parent {
+      display: grid;
+      grid-template-columns: 10px 10px;
+      grid-template-rows: 10px 10px;
+    }
+    </style>
+    <div id="parent">
       <div id="child1">Child 1</div>
       <div id="child2">Child 2</div>
       <div id="child3">Child 3</div>
@@ -38,7 +45,14 @@
 
 TEST_F(NGLayoutTest, TestNGGridChildIteratorWithOrderReversed) {
   SetBodyInnerHTML(R"HTML(
-    <div id="parent" style="display: grid">
+    <style>
+    #parent {
+      display: grid;
+      grid-template-columns: 10px 10px;
+      grid-template-rows: 10px 10px;
+    }
+    </style>
+    <div id="parent">
       <div id="child1" style="order: 4">Child 1</div>
       <div id="child2" style="order: 3">Child 2</div>
       <div id="child3" style="order: 2">Child 3</div>
@@ -66,7 +80,14 @@
 
 TEST_F(NGLayoutTest, TestNGGridChildIteratorWithOrderMixed) {
   SetBodyInnerHTML(R"HTML(
-    <div id="parent" style="display: grid">
+    <style>
+    #parent {
+      display: grid;
+      grid-template-columns: 10px 10px;
+      grid-template-rows: 10px 10px;
+    }
+    </style>
+    <div id="parent"">
       <div id="child1" style="order: 3">Child 1</div>
       <div id="child2" style="order: 3">Child 2</div>
       <div id="child3" style="order: -1">Child 3</div>
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
index 612c242..c565a23 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_child_iterator.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
 #include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
 
 namespace blink {
@@ -57,6 +58,11 @@
 
       case GridLayoutAlgorithmState::kResolvingBlockSize:
         ComputeUsedTrackSizes(GridTrackSizingDirection::kForRows);
+        state_ = GridLayoutAlgorithmState::kPlacingGridItems;
+        break;
+
+      case GridLayoutAlgorithmState::kPlacingGridItems:
+        PlaceGridItems();
         state_ = GridLayoutAlgorithmState::kCompletedLayout;
         break;
 
@@ -65,6 +71,10 @@
         break;
     }
   }
+
+  // TODO(kschmi): Calculate correct block-size.
+  container_builder_.SetFragmentsTotalBlockSize(LayoutUnit());
+  NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), &container_builder_).Run();
   return container_builder_.ToBoxFragment();
 }
 
@@ -162,7 +172,11 @@
 void NGGridLayoutAlgorithm::SetSpecifiedTracks() {
   const ComputedStyle& grid_style = Style();
   // TODO(kschmi): Auto track repeat count should be based on the number of
-  // children, rather than specified auto-column/track.
+  // children, rather than specified auto-column/track. Temporarily assign them
+  // to zero here to avoid DCHECK's until we implement this logic.
+  automatic_column_repetitions_ = 0;
+  automatic_row_repetitions_ = 0;
+
   // TODO(janewman): We need to implement calculation for track auto repeat
   // count so this can be used outside of testing.
   block_column_track_collection_.SetSpecifiedTracks(
@@ -284,10 +298,80 @@
   automatic_column_repetitions_ = auto_column;
   automatic_row_repetitions_ = auto_row;
 }
+
 wtf_size_t NGGridLayoutAlgorithm::AutoRepeatCountForDirection(
     GridTrackSizingDirection direction) const {
   return (direction == kForColumns) ? automatic_column_repetitions_
                                     : automatic_row_repetitions_;
 }
 
+void NGGridLayoutAlgorithm::PlaceGridItems() {
+  NGGridChildIterator iterator(Node());
+  LayoutUnit current_inline_offset, current_block_offset;
+
+  for (auto row_set_iterator = TrackCollection(kForRows).GetSetIterator();
+       !row_set_iterator.IsAtEnd(); row_set_iterator.MoveToNextSet()) {
+    LayoutUnit row_base_size = row_set_iterator.CurrentSet().BaseSize();
+    current_inline_offset = LayoutUnit();
+
+    for (auto column_set_iterator =
+             TrackCollection(kForColumns).GetSetIterator();
+         !column_set_iterator.IsAtEnd(); column_set_iterator.MoveToNextSet()) {
+      LayoutUnit column_base_size = column_set_iterator.CurrentSet().BaseSize();
+
+      const NGBlockNode child_node = iterator.NextChild();
+      if (!child_node)
+        return;  // TODO(kschmi): DCHECK when auto rows/columns are implemented.
+
+      if (child_node.IsOutOfFlowPositioned()) {
+        // TODO(kschmi): Pass correct static positioned offset in.
+        container_builder_.AddOutOfFlowChildCandidate(child_node,
+                                                      LogicalOffset());
+        continue;
+      }
+
+      // Layout child nodes based on constraint space from grid row/column
+      // definitions and the inline and block offsets being accumulated.
+      NGConstraintSpaceBuilder space_builder(
+          ConstraintSpace(), child_node.Style().GetWritingMode(),
+          /* is_new_fc */ true);
+      space_builder.SetIsPaintedAtomically(true);
+      space_builder.SetAvailableSize(
+          LogicalSize(column_base_size, row_base_size));
+      space_builder.SetPercentageResolutionSize(
+          LogicalSize(column_base_size, row_base_size));
+      space_builder.SetTextDirection(child_node.Style().Direction());
+      space_builder.SetIsShrinkToFit(
+          child_node.Style().LogicalWidth().IsAuto());
+      NGConstraintSpace constraint_space = space_builder.ToConstraintSpace();
+      scoped_refptr<const NGLayoutResult> result =
+          child_node.Layout(constraint_space);
+
+      container_builder_.AddChild(
+          result->PhysicalFragment(),
+          {current_inline_offset, current_block_offset});
+
+      // TODO(kschmi): row-gap and column-gap should be accounted for in
+      // inline and block positioning.
+      current_inline_offset += column_base_size;
+    }
+    current_block_offset += row_base_size;
+  }
+
+  // TODO(kschmi): There should not be any remaining children, as grid auto
+  // rows and columns should be expanded to handle all children. However, as
+  // that functionality isn't implemented yet, it is currently possible to
+  // have more children than available rows and columns. For now, place these
+  // children at (0, 0). This should be turned into an assert that no children
+  // remain in the iterator after the above loops have completed iterating over
+  // rows and columns.
+  while (const NGBlockNode child_node = iterator.NextChild()) {
+    NGConstraintSpace constraint_space = BuildSpaceForGridItem(child_node);
+    scoped_refptr<const NGLayoutResult> result =
+        child_node.Layout(constraint_space);
+    container_builder_.AddChild(result->PhysicalFragment(),
+                                {LayoutUnit(), LayoutUnit()});
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
index b81802f..0073e5d 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h
@@ -35,6 +35,7 @@
     kMeasuringItems,
     kResolvingInlineSize,
     kResolvingBlockSize,
+    kPlacingGridItems,
     kCompletedLayout
   };
 
@@ -69,6 +70,9 @@
   wtf_size_t AutoRepeatCountForDirection(
       GridTrackSizingDirection direction) const;
 
+  // Lays out and computes inline and block offsets for grid items.
+  void PlaceGridItems();
+
   Vector<GridItemData> items_;
   GridLayoutAlgorithmState state_;
   LogicalSize child_percentage_size_;
diff --git a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
index 36240d5..1ab6bd8 100644
--- a/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm_test.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
 
 namespace blink {
@@ -103,6 +104,31 @@
     return growth_limits;
   }
 
+  scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
+      Element* element) {
+    NGBlockNode container(ToLayoutBox(element->GetLayoutObject()));
+    NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+        WritingMode::kHorizontalTb, TextDirection::kLtr,
+        LogicalSize(LayoutUnit(1000), kIndefiniteSize),
+        /* shrink_to_fit */ false,
+        /* is_new_formatting_context */ true);
+    return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space);
+  }
+
+  String DumpFragmentTree(Element* element) {
+    auto fragment = RunBlockLayoutAlgorithm(element);
+    return DumpFragmentTree(fragment.get());
+  }
+
+  String DumpFragmentTree(const blink::NGPhysicalBoxFragment* fragment) {
+    NGPhysicalFragment::DumpFlags flags =
+        NGPhysicalFragment::DumpHeaderText | NGPhysicalFragment::DumpSubtree |
+        NGPhysicalFragment::DumpIndentation | NGPhysicalFragment::DumpOffset |
+        NGPhysicalFragment::DumpSize;
+
+    return fragment->DumpFragmentTree(flags);
+  }
+
   scoped_refptr<ComputedStyle> style_;
 };
 
@@ -343,8 +369,8 @@
     <style>
     #grid1 {
       display: grid;
-      grid-template-columns: 5px repeat(auto-fit, 150px) repeat(3, 10px);
-      grid-template-rows: repeat(20, 100px);
+      grid-template-columns: 5px repeat(auto-fit, 150px) repeat(3, 10px) 10px 10px;
+      grid-template-rows: repeat(20, 100px) 10px 10px;
     }
     </style>
     <div id="grid1">
@@ -373,6 +399,11 @@
   NGGridTrackCollectionBase::RangeRepeatIterator row_iterator(
       &algorithm.RowTrackCollection(), 0u);
   EXPECT_RANGE(0u, 20u, row_iterator);
+  EXPECT_TRUE(row_iterator.MoveToNextRange());
+
+  EXPECT_RANGE(20u, 1u, row_iterator);
+  EXPECT_TRUE(row_iterator.MoveToNextRange());
+  EXPECT_RANGE(21u, 1u, row_iterator);
   EXPECT_FALSE(row_iterator.MoveToNextRange());
 
   NGGridTrackCollectionBase::RangeRepeatIterator column_iterator(
@@ -381,10 +412,13 @@
   EXPECT_RANGE(0u, 1u, column_iterator);
   EXPECT_TRUE(column_iterator.MoveToNextRange());
 
-  EXPECT_COLLAPSED_RANGE(1u, 3u, column_iterator);
+  EXPECT_RANGE(1u, 3u, column_iterator);
   EXPECT_TRUE(column_iterator.MoveToNextRange());
 
-  EXPECT_RANGE(4u, 3u, column_iterator);
+  EXPECT_RANGE(4u, 1u, column_iterator);
+  EXPECT_TRUE(column_iterator.MoveToNextRange());
+
+  EXPECT_RANGE(5u, 1u, column_iterator);
   EXPECT_FALSE(column_iterator.MoveToNextRange());
 }
 
@@ -582,4 +616,53 @@
     EXPECT_EQ(expected_row_growth_limits[i], growth_limits[i]);
 }
 
+TEST_F(NGGridLayoutAlgorithmTest, FixedSizePositioning) {
+  if (!RuntimeEnabledFeatures::LayoutNGGridEnabled())
+    return;
+
+  LoadAhem();
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      body {
+        font: 10px/1 Ahem;
+      }
+
+      #grid {
+        display: grid;
+        width: 200px;
+        height: 200px;
+        grid-template-columns: 100px 100px;
+        grid-template-rows: 100px 100px;
+      }
+
+      .grid_item {
+        width: 100px;
+        height: 100px;
+        background-color: gray;
+      }
+
+    </style>
+    <div id="grid">
+      <div class="grid_item">1</div>
+      <div class="grid_item">2</div>
+      <div class="grid_item">3</div>
+      <div class="grid_item">4</div>
+    </div>
+  )HTML");
+  String dump = DumpFragmentTree(GetElementById("grid"));
+
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:200x200
+    offset:0,0 size:100x100
+      offset:0,0 size:10x10
+    offset:0,100 size:100x100
+      offset:0,0 size:10x10
+    offset:0,200 size:100x100
+      offset:0,0 size:10x10
+    offset:0,300 size:100x100
+      offset:0,0 size:10x10
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 051cd61..7dfce6e 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/flex/ng_flex_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
+#include "third_party/blink/renderer/core/layout/ng/grid/ng_grid_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
 #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
 #include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
@@ -155,6 +156,9 @@
     CreateAlgorithmAndRun<NGCustomLayoutAlgorithm>(params, callback);
   } else if (box.IsMathML()) {
     DetermineMathMLAlgorithmAndRun(box, params, callback);
+  } else if (box.IsLayoutNGGrid() &&
+             RuntimeEnabledFeatures::LayoutNGGridEnabled()) {
+    CreateAlgorithmAndRun<NGGridLayoutAlgorithm>(params, callback);
   } else if (box.IsLayoutNGFieldset()) {
     CreateAlgorithmAndRun<NGFieldsetLayoutAlgorithm>(params, callback);
     // If there's a legacy layout box, we can only do block fragmentation if
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index 4f9d57d..0a28200 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -118,7 +118,7 @@
   }
 
   const ContentSecurityPolicy* csp =
-      GetContentSecurityPolicyForWorld(options.world.get());
+      GetContentSecurityPolicyForWorld(options.world_for_csp.get());
   if (csp &&
       !csp->AllowRequest(request_context, request_destination, url,
                          options.content_security_policy_nonce,
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 09d3777d..68347031 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -689,7 +689,7 @@
   AddClientHintsIfNecessary(hints_preferences, resource_width, request);
 
   const ContentSecurityPolicy* csp =
-      GetContentSecurityPolicyForWorld(options.world.get());
+      GetContentSecurityPolicyForWorld(options.world_for_csp.get());
   if (csp && csp->ShouldSendCSPHeader(type))
     // TODO(crbug.com/993769): Test if this header returns duplicated values
     // (i.e. "CSP: active, active") on asynchronous "stale-while-revalidate"
diff --git a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
index c1593e5..15e0d4b 100644
--- a/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/scrolling_test.cc
@@ -231,6 +231,8 @@
 }
 
 TEST_P(ScrollingTest, fastFractionalScrollingDiv) {
+  ScopedFractionalScrollOffsetsForTest fractional_scroll_offsets(true);
+
   RegisterMockedHttpURLLoad("fractional-scroll-div.html");
   NavigateTo(base_url_ + "fractional-scroll-div.html");
   ForceFullCompositingUpdate();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index cb0bc6a..710f944 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -1929,7 +1929,8 @@
   if (!bitmap_image)
     return String();
 
-  sk_sp<SkImage> image = bitmap_image->PaintImageForCurrentFrame().GetSkImage();
+  sk_sp<SkImage> image =
+      bitmap_image->PaintImageForCurrentFrame().GetSwSkImage();
   if (!image || image->width() <= 0 || image->height() <= 0)
     return String();
 
@@ -1947,12 +1948,18 @@
   int width = std::round(image->width() * scale);
   int height = std::round(image->height() * scale);
 
-  // Draw the scaled image into a bitmap in native format.
+  // Draw the image into a bitmap in native format.
   SkBitmap bitmap;
-  bitmap.allocPixels(SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
-  SkCanvas canvas(bitmap);
-  canvas.clear(SK_ColorTRANSPARENT);
-  canvas.drawImageRect(image, SkRect::MakeIWH(width, height), nullptr);
+  SkPixmap unscaled_pixmap;
+  if (scale == 1.0 && image->peekPixels(&unscaled_pixmap)) {
+    bitmap.installPixels(unscaled_pixmap);
+  } else {
+    bitmap.allocPixels(
+        SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType));
+    SkCanvas canvas(bitmap);
+    canvas.clear(SK_ColorTRANSPARENT);
+    canvas.drawImageRect(image, SkRect::MakeIWH(width, height), nullptr);
+  }
 
   // Copy the bits into a buffer in RGBA_8888 unpremultiplied format
   // for encoding.
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 22a0816d6..b0975c59 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -809,6 +809,15 @@
                       WebFeature::kPaymentRequestShowWithoutGesture);
   }
 
+  // TODO(crbug.com/825270): Pretend that a user gesture is provided to allow
+  // origins that are part of the Secure Payment Confirmation Origin Trial to
+  // use skip-the-sheet flow as a hack for secure modal window
+  // (crbug.com/1122028). Remove this after user gesture delegation ships.
+  if (RuntimeEnabledFeatures::SecurePaymentConfirmationEnabled(
+          GetExecutionContext())) {
+    is_user_gesture = true;
+  }
+
   // TODO(crbug.com/779126): add support for handling payment requests in
   // immersive mode.
   if (GetFrame()->GetDocument()->GetSettings()->GetImmersiveModeEnabled()) {
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
index 7bced30a..1104343 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
+++ b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_client.h
@@ -35,6 +35,11 @@
                     const String& url,
                     int error_code,
                     const String& error_text));
+  MOCK_METHOD4(DidChangeSessionDescriptions,
+               void(RTCSessionDescriptionPlatform*,
+                    RTCSessionDescriptionPlatform*,
+                    RTCSessionDescriptionPlatform*,
+                    RTCSessionDescriptionPlatform*));
   MOCK_METHOD1(DidChangeSignalingState,
                void(webrtc::PeerConnectionInterface::SignalingState state));
   MOCK_METHOD1(DidChangeIceGatheringState,
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
index 5437abb2..da6d4bb 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
+++ b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.cc
@@ -286,36 +286,6 @@
     RTCVoidRequest*,
     RTCSessionDescriptionPlatform*) {}
 
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::LocalDescription() {
-  return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::RemoteDescription() {
-  return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::CurrentLocalDescription() {
-  return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::CurrentRemoteDescription() {
-  return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::PendingLocalDescription() {
-  return nullptr;
-}
-
-RTCSessionDescriptionPlatform*
-MockRTCPeerConnectionHandlerPlatform::PendingRemoteDescription() {
-  return nullptr;
-}
-
 const webrtc::PeerConnectionInterface::RTCConfiguration&
 MockRTCPeerConnectionHandlerPlatform::GetConfiguration() const {
   static const webrtc::PeerConnectionInterface::RTCConfiguration configuration;
diff --git a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
index 71fadfd1..1a9cb0f 100644
--- a/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
+++ b/third_party/blink/renderer/modules/peerconnection/mock_rtc_peer_connection_handler_platform.h
@@ -48,12 +48,6 @@
                            RTCSessionDescriptionPlatform*) override;
   void SetRemoteDescription(RTCVoidRequest*,
                             RTCSessionDescriptionPlatform*) override;
-  RTCSessionDescriptionPlatform* LocalDescription() override;
-  RTCSessionDescriptionPlatform* RemoteDescription() override;
-  RTCSessionDescriptionPlatform* CurrentLocalDescription() override;
-  RTCSessionDescriptionPlatform* CurrentRemoteDescription() override;
-  RTCSessionDescriptionPlatform* PendingLocalDescription() override;
-  RTCSessionDescriptionPlatform* PendingRemoteDescription() override;
   const webrtc::PeerConnectionInterface::RTCConfiguration& GetConfiguration()
       const override;
   webrtc::RTCErrorType SetConfiguration(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index cd98310..aa15ab5 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -746,6 +746,10 @@
     MediaConstraints constraints,
     ExceptionState& exception_state)
     : ExecutionContextLifecycleObserver(context),
+      pending_local_description_(nullptr),
+      current_local_description_(nullptr),
+      pending_remote_description_(nullptr),
+      current_remote_description_(nullptr),
       signaling_state_(
           webrtc::PeerConnectionInterface::SignalingState::kStable),
       ice_gathering_state_(webrtc::PeerConnectionInterface::kIceGatheringNew),
@@ -1459,28 +1463,17 @@
   return ScriptPromise::CastUndefined(script_state);
 }
 
-RTCSessionDescription* RTCPeerConnection::localDescription() {
-  auto* platform_session_description = peer_handler_->LocalDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::localDescription() const {
+  return pending_local_description_ ? pending_local_description_
+                                    : current_local_description_;
 }
 
-RTCSessionDescription* RTCPeerConnection::currentLocalDescription() {
-  auto* platform_session_description = peer_handler_->CurrentLocalDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::currentLocalDescription() const {
+  return current_local_description_;
 }
 
-RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() {
-  auto* platform_session_description = peer_handler_->PendingLocalDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::pendingLocalDescription() const {
+  return pending_local_description_;
 }
 
 ScriptPromise RTCPeerConnection::setRemoteDescription(
@@ -1587,30 +1580,17 @@
   return ScriptPromise::CastUndefined(script_state);
 }
 
-RTCSessionDescription* RTCPeerConnection::remoteDescription() {
-  auto* platform_session_description = peer_handler_->RemoteDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::remoteDescription() const {
+  return pending_remote_description_ ? pending_remote_description_
+                                     : current_remote_description_;
 }
 
-RTCSessionDescription* RTCPeerConnection::currentRemoteDescription() {
-  auto* platform_session_description =
-      peer_handler_->CurrentRemoteDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::currentRemoteDescription() const {
+  return current_remote_description_;
 }
 
-RTCSessionDescription* RTCPeerConnection::pendingRemoteDescription() {
-  auto* platform_session_description =
-      peer_handler_->PendingRemoteDescription();
-  if (!platform_session_description)
-    return nullptr;
-
-  return RTCSessionDescription::Create(platform_session_description);
+RTCSessionDescription* RTCPeerConnection::pendingRemoteDescription() const {
+  return pending_remote_description_;
 }
 
 RTCConfiguration* RTCPeerConnection::getConfiguration(
@@ -2034,7 +2014,7 @@
 }
 
 base::Optional<bool> RTCPeerConnection::canTrickleIceCandidates() const {
-  if (closed_ || !peer_handler_->RemoteDescription()) {
+  if (closed_ || !remoteDescription()) {
     return base::nullopt;
   }
   webrtc::PeerConnectionInterface* native_connection =
@@ -2894,6 +2874,31 @@
       address, port, host_candidate, url, error_code, error_text));
 }
 
+void RTCPeerConnection::DidChangeSessionDescriptions(
+    RTCSessionDescriptionPlatform* pending_local_description,
+    RTCSessionDescriptionPlatform* current_local_description,
+    RTCSessionDescriptionPlatform* pending_remote_description,
+    RTCSessionDescriptionPlatform* current_remote_description) {
+  DCHECK(!closed_);
+  DCHECK(GetExecutionContext()->IsContextThread());
+  pending_local_description_ =
+      pending_local_description
+          ? RTCSessionDescription::Create(pending_local_description)
+          : nullptr;
+  current_local_description_ =
+      current_local_description
+          ? RTCSessionDescription::Create(current_local_description)
+          : nullptr;
+  pending_remote_description_ =
+      pending_remote_description
+          ? RTCSessionDescription::Create(pending_remote_description)
+          : nullptr;
+  current_remote_description_ =
+      current_remote_description
+          ? RTCSessionDescription::Create(current_remote_description)
+          : nullptr;
+}
+
 void RTCPeerConnection::DidChangeSignalingState(
     webrtc::PeerConnectionInterface::SignalingState new_state) {
   DCHECK(!closed_);
@@ -3545,6 +3550,10 @@
 }
 
 void RTCPeerConnection::Trace(Visitor* visitor) const {
+  visitor->Trace(pending_local_description_);
+  visitor->Trace(current_local_description_);
+  visitor->Trace(pending_remote_description_);
+  visitor->Trace(current_remote_description_);
   visitor->Trace(tracks_);
   visitor->Trace(rtp_senders_);
   visitor->Trace(rtp_receivers_);
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index 72ead12..7a57fc97 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -183,9 +183,9 @@
       const RTCSessionDescriptionInit*,
       V8VoidFunction*,
       V8RTCPeerConnectionErrorCallback* = nullptr);
-  RTCSessionDescription* localDescription();
-  RTCSessionDescription* currentLocalDescription();
-  RTCSessionDescription* pendingLocalDescription();
+  RTCSessionDescription* localDescription() const;
+  RTCSessionDescription* currentLocalDescription() const;
+  RTCSessionDescription* pendingLocalDescription() const;
 
   ScriptPromise setRemoteDescription(ScriptState*,
                                      const RTCSessionDescriptionInit*,
@@ -195,9 +195,9 @@
       const RTCSessionDescriptionInit*,
       V8VoidFunction*,
       V8RTCPeerConnectionErrorCallback* = nullptr);
-  RTCSessionDescription* remoteDescription();
-  RTCSessionDescription* currentRemoteDescription();
-  RTCSessionDescription* pendingRemoteDescription();
+  RTCSessionDescription* remoteDescription() const;
+  RTCSessionDescription* currentRemoteDescription() const;
+  RTCSessionDescription* pendingRemoteDescription() const;
 
   String signalingState() const;
 
@@ -337,6 +337,11 @@
                            const String& url,
                            int error_code,
                            const String& error_text) override;
+  void DidChangeSessionDescriptions(
+      RTCSessionDescriptionPlatform* pending_local_description,
+      RTCSessionDescriptionPlatform* current_local_description,
+      RTCSessionDescriptionPlatform* pending_remote_description,
+      RTCSessionDescriptionPlatform* current_remote_description) override;
   void DidChangeSignalingState(
       webrtc::PeerConnectionInterface::SignalingState) override;
   void DidChangeIceGatheringState(
@@ -571,6 +576,10 @@
 
   HeapHashSet<Member<RTCIceTransport>> ActiveIceTransports() const;
 
+  Member<RTCSessionDescription> pending_local_description_;
+  Member<RTCSessionDescription> current_local_description_;
+  Member<RTCSessionDescription> pending_remote_description_;
+  Member<RTCSessionDescription> current_remote_description_;
   webrtc::PeerConnectionInterface::SignalingState signaling_state_;
   webrtc::PeerConnectionInterface::IceGatheringState ice_gathering_state_;
   webrtc::PeerConnectionInterface::IceConnectionState ice_connection_state_;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index 373be00..6e19f59 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -154,29 +154,6 @@
   event->Signal();
 }
 
-// Initializes |description| if |description_callback| returns non-null,
-// otherwise does nothing.
-void GetRTCSessionDescriptionPlatformFromSessionDescriptionCallback(
-    CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-        description_callback,
-    std::string* out_type,
-    std::string* out_sdp,
-    bool* success) {
-  DCHECK(out_type);
-  DCHECK(out_sdp);
-  DCHECK(success);
-
-  const webrtc::SessionDescriptionInterface* description =
-      std::move(description_callback).Run();
-  if (description) {
-    std::string sdp;
-    description->ToString(&sdp);
-    *out_type = description->type();
-    *out_sdp = sdp;
-    *success = true;
-  }
-}
-
 // Converter functions from Blink types to WebRTC types.
 
 absl::optional<bool> ConstraintToOptional(
@@ -702,19 +679,14 @@
           pending_local_description(states.pending_local_description.release());
       std::unique_ptr<webrtc::SessionDescriptionInterface>
           current_local_description(states.current_local_description.release());
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          pending_remote_description(
+              states.pending_remote_description.release());
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          current_remote_description(
+              states.current_remote_description.release());
 
-      // Process the rest of the state changes differently depending on SDP
-      // semantics.
-      if (sdp_semantics_ == webrtc::SdpSemantics::kPlanB) {
-        ProcessStateChangesPlanB(std::move(states));
-      } else {
-        DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kUnifiedPlan);
-        ProcessStateChangesUnifiedPlan(std::move(states));
-      }
-
-      // |handler_| can become null after this call.
-      handler_->OnSignalingChange(signaling_state);
-
+      // Track result in chrome://webrtc-internals/.
       if (tracker_ && handler_) {
         StringBuilder value;
         if (action_ ==
@@ -754,6 +726,24 @@
         tracker_->TrackSessionDescriptionCallback(
             handler_.get(), action_, "OnSuccess", value.ToString());
       }
+
+      handler_->OnSessionDescriptionsUpdated(
+          std::move(pending_local_description),
+          std::move(current_local_description),
+          std::move(pending_remote_description),
+          std::move(current_remote_description));
+
+      // Process the rest of the state changes differently depending on SDP
+      // semantics.
+      if (sdp_semantics_ == webrtc::SdpSemantics::kPlanB) {
+        ProcessStateChangesPlanB(std::move(states));
+      } else {
+        DCHECK_EQ(sdp_semantics_, webrtc::SdpSemantics::kUnifiedPlan);
+        ProcessStateChangesUnifiedPlan(std::move(states));
+      }
+
+      // |handler_| can become null after this call.
+      handler_->OnSignalingChange(signaling_state);
     }
     if (action_ == PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION) {
       // Resolve the promise in a post to ensure any events scheduled for
@@ -1495,81 +1485,6 @@
           CrossThreadUnretained("SetRemoteDescription")));
 }
 
-RTCSessionDescriptionPlatform* RTCPeerConnectionHandler::LocalDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::localDescription");
-
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::local_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "localDescription");
-}
-
-RTCSessionDescriptionPlatform* RTCPeerConnectionHandler::RemoteDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::remoteDescription");
-
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::remote_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "remoteDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::CurrentLocalDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::currentLocalDescription");
-
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::current_local_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "currentLocalDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::CurrentRemoteDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::currentRemoteDescription");
-
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::current_remote_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "currentRemoteDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::PendingLocalDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::pendingLocalDescription");
-
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::pending_local_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "pendingLocalDescription");
-}
-
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::PendingRemoteDescription() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::pendingRemoteDescription");
-  CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-      description_cb = CrossThreadBindOnce(
-          &webrtc::PeerConnectionInterface::pending_remote_description,
-          native_peer_connection_);
-  return GetRTCSessionDescriptionPlatformOnSignalingThread(
-      std::move(description_cb), "pendingRemoteDescription");
-}
-
 const webrtc::PeerConnectionInterface::RTCConfiguration&
 RTCPeerConnectionHandler::GetConfiguration() const {
   return configuration_;
@@ -1620,6 +1535,14 @@
   auto callback_on_task_runner =
       [](base::WeakPtr<RTCPeerConnectionHandler> handler_weak_ptr,
          base::WeakPtr<PeerConnectionTracker> tracker_weak_ptr,
+         std::unique_ptr<webrtc::SessionDescriptionInterface>
+             pending_local_description,
+         std::unique_ptr<webrtc::SessionDescriptionInterface>
+             current_local_description,
+         std::unique_ptr<webrtc::SessionDescriptionInterface>
+             pending_remote_description,
+         std::unique_ptr<webrtc::SessionDescriptionInterface>
+             current_remote_description,
          RTCIceCandidatePlatform* candidate, webrtc::RTCError result,
          RTCVoidRequest* request) {
         // Inform tracker (chrome://webrtc-internals).
@@ -1628,6 +1551,14 @@
               handler_weak_ptr.get(), candidate,
               PeerConnectionTracker::SOURCE_REMOTE, result.ok());
         }
+        // Update session descriptions.
+        if (handler_weak_ptr) {
+          handler_weak_ptr->OnSessionDescriptionsUpdated(
+              std::move(pending_local_description),
+              std::move(current_local_description),
+              std::move(pending_remote_description),
+              std::move(current_remote_description));
+        }
         // Resolve promise.
         if (result.ok())
           request->RequestSucceeded();
@@ -1637,12 +1568,26 @@
 
   native_peer_connection_->AddIceCandidate(
       std::move(native_candidate),
-      [task_runner = task_runner_,
+      [pc = native_peer_connection_, task_runner = task_runner_,
        handler_weak_ptr = weak_factory_.GetWeakPtr(),
        tracker_weak_ptr = peer_connection_tracker_, candidate,
        persistent_request = WrapCrossThreadPersistent(request),
        callback_on_task_runner =
            std::move(callback_on_task_runner)](webrtc::RTCError result) {
+        // Grab a snapshot of all the session descriptions. AddIceCandidate may
+        // have modified the remote description.
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            pending_local_description =
+                CopySessionDescription(pc->pending_local_description());
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            current_local_description =
+                CopySessionDescription(pc->current_local_description());
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            pending_remote_description =
+                CopySessionDescription(pc->pending_remote_description());
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            current_remote_description =
+                CopySessionDescription(pc->current_remote_description());
         // This callback is invoked on the webrtc signaling thread (this is true
         // in production, not in rtc_peer_connection_handler_test.cc which uses
         // a fake |native_peer_connection_|). Jump back to the renderer thread.
@@ -1650,8 +1595,12 @@
             *task_runner, FROM_HERE,
             WTF::CrossThreadBindOnce(
                 std::move(callback_on_task_runner), handler_weak_ptr,
-                tracker_weak_ptr, WrapCrossThreadPersistent(candidate),
-                std::move(result), std::move(persistent_request)));
+                tracker_weak_ptr, std::move(pending_local_description),
+                std::move(current_local_description),
+                std::move(pending_remote_description),
+                std::move(current_remote_description),
+                WrapCrossThreadPersistent(candidate), std::move(result),
+                std::move(persistent_request)));
       });
 }
 
@@ -2224,6 +2173,32 @@
   }
 }
 
+void RTCPeerConnectionHandler::OnSessionDescriptionsUpdated(
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        pending_local_description,
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        current_local_description,
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        pending_remote_description,
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        current_remote_description) {
+  if (!client_ || is_closed_)
+    return;
+  client_->DidChangeSessionDescriptions(
+      pending_local_description
+          ? CreateWebKitSessionDescription(pending_local_description.get())
+          : nullptr,
+      current_local_description
+          ? CreateWebKitSessionDescription(current_local_description.get())
+          : nullptr,
+      pending_remote_description
+          ? CreateWebKitSessionDescription(pending_remote_description.get())
+          : nullptr,
+      current_remote_description
+          ? CreateWebKitSessionDescription(current_remote_description.get())
+          : nullptr);
+}
+
 void RTCPeerConnectionHandler::OnSignalingChange(
     webrtc::PeerConnectionInterface::SignalingState new_state) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
@@ -2707,35 +2682,6 @@
   return dependency_factory_->GetWebRtcSignalingTaskRunner();
 }
 
-RTCSessionDescriptionPlatform*
-RTCPeerConnectionHandler::GetRTCSessionDescriptionPlatformOnSignalingThread(
-    CrossThreadOnceFunction<const webrtc::SessionDescriptionInterface*()>
-        description_cb,
-    const char* log_text) {
-  // Since the webrtc::PeerConnectionInterface::*_description() functions
-  // return a pointer to a non-reference-counted object that lives on the
-  // signaling thread, we cannot fetch a pointer to it and use it directly
-  // here.
-  // Instead, we access the object completely on the signaling thread.
-  // Initializing |description| on the signaling thread is safe because we
-  // own it and wait for it to be initialized here.
-
-  std::string type, sdp;
-  bool success = false;
-  RunSynchronousOnceClosureOnSignalingThread(
-      CrossThreadBindOnce(
-          &GetRTCSessionDescriptionPlatformFromSessionDescriptionCallback,
-          std::move(description_cb), CrossThreadUnretained(&type),
-          CrossThreadUnretained(&sdp), CrossThreadUnretained(&success)),
-      log_text);
-
-  if (!success)
-    return nullptr;
-
-  return MakeGarbageCollected<RTCSessionDescriptionPlatform>(
-      String::FromUTF8(type), String::FromUTF8(sdp));
-}
-
 void RTCPeerConnectionHandler::ReportICEState(
     webrtc::PeerConnectionInterface::IceConnectionState new_state) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
index f2fe772..17ca1e4 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.h
@@ -154,13 +154,6 @@
   virtual void SetRemoteDescription(blink::RTCVoidRequest* request,
                                     RTCSessionDescriptionPlatform* description);
 
-  virtual RTCSessionDescriptionPlatform* LocalDescription();
-  virtual RTCSessionDescriptionPlatform* RemoteDescription();
-  virtual RTCSessionDescriptionPlatform* CurrentLocalDescription();
-  virtual RTCSessionDescriptionPlatform* CurrentRemoteDescription();
-  virtual RTCSessionDescriptionPlatform* PendingLocalDescription();
-  virtual RTCSessionDescriptionPlatform* PendingRemoteDescription();
-
   virtual const webrtc::PeerConnectionInterface::RTCConfiguration&
   GetConfiguration() const;
   virtual webrtc::RTCErrorType SetConfiguration(
@@ -259,6 +252,15 @@
   class SetLocalDescriptionRequest;
   friend class SetLocalDescriptionRequest;
 
+  void OnSessionDescriptionsUpdated(
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          pending_local_description,
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          current_local_description,
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          pending_remote_description,
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          current_remote_description);
   void OnSignalingChange(
       webrtc::PeerConnectionInterface::SignalingState new_state);
   void OnIceConnectionChange(
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
index 62b37513..bab93c40 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler_test.cc
@@ -676,8 +676,6 @@
 
   pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
   RunMessageLoopsUntilIdle();
-  EXPECT_EQ(description->GetType(), pc_handler_->LocalDescription()->GetType());
-  EXPECT_EQ(description->Sdp(), pc_handler_->LocalDescription()->Sdp());
 
   std::string sdp_string;
   ASSERT_TRUE(mock_peer_connection_->local_description());
@@ -711,8 +709,6 @@
   mock_dependency_factory_->SetFailToCreateSessionDescription(true);
   pc_handler_->SetLocalDescription(nullptr /*RTCVoidRequest*/, description);
   RunMessageLoopsUntilIdle();
-  // A description that failed to be applied shouldn't be stored.
-  EXPECT_TRUE(!pc_handler_->LocalDescription());
 }
 
 TEST_F(RTCPeerConnectionHandlerTest, setRemoteDescription) {
@@ -730,9 +726,6 @@
 
   pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
   RunMessageLoopsUntilIdle();
-  EXPECT_EQ(description->GetType(),
-            pc_handler_->RemoteDescription()->GetType());
-  EXPECT_EQ(description->Sdp(), pc_handler_->RemoteDescription()->Sdp());
 
   std::string sdp_string;
   ASSERT_TRUE(mock_peer_connection_->remote_description());
@@ -766,8 +759,6 @@
   mock_dependency_factory_->SetFailToCreateSessionDescription(true);
   pc_handler_->SetRemoteDescription(nullptr /*RTCVoidRequest*/, description);
   RunMessageLoopsUntilIdle();
-  // A description that failed to be applied shouldn't be stored.
-  EXPECT_TRUE(!pc_handler_->RemoteDescription());
 }
 
 TEST_F(RTCPeerConnectionHandlerTest, setConfiguration) {
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc b/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
index f4f9a15d..77f65fb 100644
--- a/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
+++ b/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.cc
@@ -6,10 +6,19 @@
 
 #include "base/bind.h"
 #include "base/check.h"
-#include "third_party/webrtc/pc/sdp_utils.h"
 
 namespace blink {
 
+std::unique_ptr<webrtc::SessionDescriptionInterface> CopySessionDescription(
+    const webrtc::SessionDescriptionInterface* description) {
+  if (!description)
+    return nullptr;
+  std::string sdp;
+  description->ToString(&sdp);
+  return std::unique_ptr<webrtc::SessionDescriptionInterface>(
+      webrtc::CreateSessionDescription(description->type(), sdp, nullptr));
+}
+
 WebRtcSetDescriptionObserver::States::States()
     : signaling_state(
           webrtc::PeerConnectionInterface::SignalingState::kClosed) {}
@@ -19,7 +28,9 @@
       sctp_transport_state(std::move(other.sctp_transport_state)),
       transceiver_states(std::move(other.transceiver_states)),
       pending_local_description(std::move(other.pending_local_description)),
-      current_local_description(std::move(other.current_local_description)) {}
+      current_local_description(std::move(other.current_local_description)),
+      pending_remote_description(std::move(other.pending_remote_description)),
+      current_remote_description(std::move(other.current_remote_description)) {}
 
 WebRtcSetDescriptionObserver::States::~States() = default;
 
@@ -30,6 +41,8 @@
   transceiver_states = std::move(other.transceiver_states);
   pending_local_description = std::move(other.pending_local_description);
   current_local_description = std::move(other.current_local_description);
+  pending_remote_description = std::move(other.pending_remote_description);
+  current_remote_description = std::move(other.current_remote_description);
   return *this;
 }
 
@@ -81,22 +94,26 @@
   transceiver_state_surfacer.Initialize(pc_, track_adapter_map_,
                                         std::move(transceivers));
   std::unique_ptr<webrtc::SessionDescriptionInterface>
-      pending_local_description = pc_->pending_local_description()
-                                      ? webrtc::CloneSessionDescription(
-                                            pc_->pending_local_description())
-                                      : nullptr;
+      pending_local_description =
+          CopySessionDescription(pc_->pending_local_description());
   std::unique_ptr<webrtc::SessionDescriptionInterface>
-      current_local_description = pc_->current_local_description()
-                                      ? webrtc::CloneSessionDescription(
-                                            pc_->current_local_description())
-                                      : nullptr;
+      current_local_description =
+          CopySessionDescription(pc_->current_local_description());
+  std::unique_ptr<webrtc::SessionDescriptionInterface>
+      pending_remote_description =
+          CopySessionDescription(pc_->pending_remote_description());
+  std::unique_ptr<webrtc::SessionDescriptionInterface>
+      current_remote_description =
+          CopySessionDescription(pc_->current_remote_description());
   main_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&WebRtcSetDescriptionObserverHandlerImpl::
                                     OnSetDescriptionCompleteOnMainThread,
                                 this, std::move(error), pc_->signaling_state(),
                                 std::move(transceiver_state_surfacer),
                                 std::move(pending_local_description),
-                                std::move(current_local_description)));
+                                std::move(current_local_description),
+                                std::move(pending_remote_description),
+                                std::move(current_remote_description)));
 }
 
 void WebRtcSetDescriptionObserverHandlerImpl::
@@ -107,7 +124,11 @@
         std::unique_ptr<webrtc::SessionDescriptionInterface>
             pending_local_description,
         std::unique_ptr<webrtc::SessionDescriptionInterface>
-            current_local_description) {
+            current_local_description,
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            pending_remote_description,
+        std::unique_ptr<webrtc::SessionDescriptionInterface>
+            current_remote_description) {
   CHECK(main_task_runner_->BelongsToCurrentThread());
   WebRtcSetDescriptionObserver::States states;
   states.signaling_state = signaling_state;
@@ -116,6 +137,8 @@
   states.transceiver_states = transceiver_state_surfacer.ObtainStates();
   states.pending_local_description = std::move(pending_local_description);
   states.current_local_description = std::move(current_local_description);
+  states.pending_remote_description = std::move(pending_remote_description);
+  states.current_remote_description = std::move(current_remote_description);
   observer_->OnSetDescriptionComplete(std::move(error), std::move(states));
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h b/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
index a8914d2..196348e2 100644
--- a/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
+++ b/third_party/blink/renderer/modules/peerconnection/webrtc_set_description_observer.h
@@ -30,6 +30,14 @@
 
 namespace blink {
 
+// Copies the session description.
+// Note: At the time of writing, third_party/webrtc/pc/sdp_utils.h's
+// webrtc::CloneSessionDescription() creates a copy that does not include
+// candidates added with AddIceCandidate. This is why we need our own copy
+// function, which copies everything.
+std::unique_ptr<webrtc::SessionDescriptionInterface> CopySessionDescription(
+    const webrtc::SessionDescriptionInterface* description);
+
 // The blink layer correspondent of the setLocalDescription() observer
 // (webrtc::SetSessionDescriptionObserver) and setRemoteDescription() observer
 // (webrtc::SetRemoteDescriptionObserverInterface). The implementation should
@@ -51,15 +59,14 @@
     webrtc::PeerConnectionInterface::SignalingState signaling_state;
     blink::WebRTCSctpTransportSnapshot sctp_transport_state;
     std::vector<blink::RtpTransceiverState> transceiver_states;
-    // For now, the session descriptions are only surfaced for the sake of
-    // showing up in chrome://webrtc-internals/ when implicit
-    // setLocalDescription() resolves.
-    // TODO(https://crbug.com/788558): Surface all states to blink at the same,
-    // time, including [current/pending][Local/Remote]Description.
     std::unique_ptr<webrtc::SessionDescriptionInterface>
         pending_local_description;
     std::unique_ptr<webrtc::SessionDescriptionInterface>
         current_local_description;
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        pending_remote_description;
+    std::unique_ptr<webrtc::SessionDescriptionInterface>
+        current_remote_description;
 
     DISALLOW_COPY_AND_ASSIGN(States);
   };
@@ -117,7 +124,11 @@
       std::unique_ptr<webrtc::SessionDescriptionInterface>
           pending_local_description,
       std::unique_ptr<webrtc::SessionDescriptionInterface>
-          current_local_description);
+          current_local_description,
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          pending_remote_description,
+      std::unique_ptr<webrtc::SessionDescriptionInterface>
+          current_remote_description);
 
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner_;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index d86d690..46ceb881 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -64,6 +64,7 @@
 #include "third_party/blink/renderer/core/fetch/global_fetch.h"
 #include "third_party/blink/renderer/core/frame/reporting_context.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
+#include "third_party/blink/renderer/core/inspector/request_debug_header_scope.h"
 #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h"
 #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
@@ -1509,6 +1510,12 @@
       !params->request->is_main_resource_load ? String() : params->client_id);
   event_init->setIsReload(params->request->is_reload);
 
+  mojom::blink::FetchAPIRequest& fetch_request = *params->request;
+  auto debug_header_it =
+      fetch_request.headers.find(RequestDebugHeaderScope::kHeaderName);
+  auto stack_string = debug_header_it == fetch_request.headers.end()
+                          ? String()
+                          : debug_header_it->value;
   Request* request = Request::Create(
       ScriptController()->GetScriptState(), std::move(params->request),
       Request::ForServiceWorkerFetchEvent::kTrue);
@@ -1532,6 +1539,7 @@
 
   NoteNewFetchEvent(request->url());
 
+  RequestDebugHeaderScope debug_header_scope(this, stack_string);
   DispatchExtendableEventWithRespondWith(fetch_event, wait_until_observer,
                                          respond_with_observer);
 }
diff --git a/third_party/blink/renderer/modules/webcodecs/video_frame.cc b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
index d5316c0..3c613b1 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_frame.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_frame.cc
@@ -94,9 +94,9 @@
   base::TimeDelta timestamp =
       base::TimeDelta::FromMicroseconds(init->timestamp());
 
-  auto sk_image =
-      source->BitmapImage()->PaintImageForCurrentFrame().GetSkImage();
-  auto sk_color_space = sk_image->refColorSpace();
+  auto sk_image_info =
+      source->BitmapImage()->PaintImageForCurrentFrame().GetSkImageInfo();
+  auto sk_color_space = sk_image_info.refColorSpace();
   if (!sk_color_space) {
     sk_color_space = SkColorSpace::MakeSRGB();
   }
@@ -105,7 +105,7 @@
                                       "Invalid color space");
     return nullptr;
   }
-  auto sk_color_type = sk_image->colorType();
+  auto sk_color_type = sk_image_info.colorType();
   if (!IsValidSkColorType(sk_color_type)) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                       "Invalid pixel format");
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
index 2ea05b8..d223fc7 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.cc
@@ -403,15 +403,13 @@
   if (!ContextProviderWrapper())
     return nullptr;
 
-  sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSkImage();
-  if (SkColorSpace::Equals(color_space.get(), skia_image->colorSpace()) &&
-      color_type == skia_image->colorType()) {
+  SkImageInfo image_info = PaintImageForCurrentFrame().GetSkImageInfo();
+  if (SkColorSpace::Equals(color_space.get(), image_info.colorSpace()) &&
+      color_type == image_info.colorType()) {
     return this;
   }
 
-  auto image_info = skia_image->imageInfo()
-                        .makeColorSpace(color_space)
-                        .makeColorType(color_type);
+  image_info = image_info.makeColorSpace(color_space).makeColorType(color_type);
 
   auto usage_flags = ContextProviderWrapper()
                          ->ContextProvider()
diff --git a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
index 5fbfd98..7d9b409 100644
--- a/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
+++ b/third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image_test.cc
@@ -81,10 +81,9 @@
 TEST_F(AcceleratedStaticBitmapImageTest, SkImageCached) {
   auto bitmap = CreateBitmap();
 
-  sk_sp<SkImage> stored_image =
-      bitmap->PaintImageForCurrentFrame().GetSkImage();
-  auto stored_image2 = bitmap->PaintImageForCurrentFrame().GetSkImage();
-  EXPECT_EQ(stored_image.get(), stored_image2.get());
+  cc::PaintImage stored_image = bitmap->PaintImageForCurrentFrame();
+  auto stored_image2 = bitmap->PaintImageForCurrentFrame();
+  EXPECT_EQ(stored_image, stored_image2);
 }
 
 TEST_F(AcceleratedStaticBitmapImageTest, CopyToTextureSynchronization) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
index 94815c0..792df54 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.cc
@@ -179,12 +179,6 @@
   }
 
   TRACE_EVENT0("blink", "Canvas2DLayerBridge::hibernate");
-  sk_sp<SkSurface> temp_hibernation_surface =
-      SkSurface::MakeRasterN32Premul(size_.Width(), size_.Height());
-  if (!temp_hibernation_surface) {
-    logger_->ReportHibernationEvent(kHibernationAbortedDueToAllocationFailure);
-    return;
-  }
   // No HibernationEvent reported on success. This is on purppose to avoid
   // non-complementary stats. Each HibernationScheduled event is paired with
   // exactly one failure or exit event.
@@ -202,9 +196,7 @@
     logger_->ReportHibernationEvent(kHibernationAbortedDueSnapshotFailure);
     return;
   }
-  temp_hibernation_surface->getCanvas()->drawImage(
-      snapshot->PaintImageForCurrentFrame().GetSkImage(), 0, 0, &copy_paint);
-  hibernation_image_ = temp_hibernation_surface->makeImageSnapshot();
+  hibernation_image_ = snapshot->PaintImageForCurrentFrame().GetSwSkImage();
   ResetResourceProvider();
   if (layer_)
     layer_->ClearTexture();
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
index c7afd34d..5067d33 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h
@@ -133,7 +133,7 @@
     kHibernationAbortedDueToVisibilityChange = 3,
     kHibernationAbortedDueGpuContextLoss = 4,
     kHibernationAbortedDueToSwitchToUnacceleratedRendering = 5,
-    kHibernationAbortedDueToAllocationFailure = 6,
+    // kHibernationAbortedDueToAllocationFailure = 6, (obsolete)
     kHibernationAbortedDueSnapshotFailure = 7,
     kHibernationEndedNormally = 8,
     kHibernationEndedWithSwitchToBackgroundRendering = 9,
diff --git a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
index 614b7c9..69053325 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge_test.cc
@@ -169,12 +169,10 @@
   std::unique_ptr<Canvas2DLayerBridge> bridge =
       MakeBridge(IntSize(300, 150), RasterMode::kCPU, CanvasColorParams());
 
-  GrBackendTexture backend_texture = bridge->NewImageSnapshot()
-                                         ->PaintImageForCurrentFrame()
-                                         .GetSkImage()
-                                         ->getBackendTexture(true);
+  bool has_backend_texture =
+      bridge->NewImageSnapshot()->PaintImageForCurrentFrame().IsTextureBacked();
 
-  EXPECT_FALSE(backend_texture.isValid());
+  EXPECT_FALSE(has_backend_texture);
 }
 
 TEST_F(Canvas2DLayerBridgeTest, NoDrawOnContextLost) {
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
index c14e10e..2d175599 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -198,9 +198,9 @@
     auto paint_image = MakeImageSnapshot();
     if (!paint_image)
       return nullptr;
-    DCHECK(!paint_image.GetSkImage()->isTextureBacked());
+    DCHECK(!paint_image.IsTextureBacked());
 
-    output_resource->TakeSkImage(paint_image.GetSkImage());
+    output_resource->TakeSkImage(paint_image.GetSwSkImage());
 
     return output_resource;
   }
@@ -349,7 +349,7 @@
     DCHECK(sk_image);
     SkPixmap map;
     // We know this SkImage is software backed because it's guaranteed by
-    // PaintImage::GetRasterSkImage above
+    // PaintImage::GetSwSkImage above
     sk_image->peekPixels(&map);
     WritePixels(map.info(), map.addr(), map.rowBytes(), /*x=*/0, /*y=*/0);
   }
@@ -1222,7 +1222,7 @@
     return nullptr;
 
   auto paint_image = MakeImageSnapshot();
-  DCHECK(!paint_image.GetSkImage()->isTextureBacked());
+  DCHECK(!paint_image.IsTextureBacked());
   return UnacceleratedStaticBitmapImage::Create(std::move(paint_image),
                                                 orientation);
 }
diff --git a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
index 0b47bc6..4dd30da 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/image_layer_bridge.cc
@@ -39,7 +39,7 @@
   auto paint_image = source->PaintImageForCurrentFrame();
   auto provider = CanvasResourceProvider::CreateSharedImageProvider(
       source->Size(), kLow_SkFilterQuality,
-      CanvasColorParams(paint_image.GetSkImage()->imageInfo()),
+      CanvasColorParams(paint_image.GetSkImageInfo()),
       CanvasResourceProvider::ShouldInitialize::kNo, context_provider_wrapper,
       RasterMode::kGPU, source->IsOriginTopLeft(),
       gpu::SHARED_IMAGE_USAGE_DISPLAY);
diff --git a/third_party/blink/renderer/platform/graphics/image.cc b/third_party/blink/renderer/platform/graphics/image.cc
index 7a577b7..41e6bec 100644
--- a/third_party/blink/renderer/platform/graphics/image.cc
+++ b/third_party/blink/renderer/platform/graphics/image.cc
@@ -155,7 +155,7 @@
 
   SkCanvas* canvas = surface->getCanvas();
   canvas->concat(AffineTransformToSkMatrix(transform));
-  canvas->drawImage(image.GetSkImage(), 0, 0, &paint);
+  canvas->drawImage(image.GetSwSkImage(), 0, 0, &paint);
 
   return PaintImageBuilder::WithProperties(std::move(image))
       .set_image(surface->makeImageSnapshot(), PaintImage::GetNextContentId())
@@ -356,7 +356,7 @@
       return {};
   }
 
-  sk_sp<SkImage> sk_image = paint_image.GetSkImage();
+  sk_sp<SkImage> sk_image = paint_image.GetSwSkImage();
   if (!sk_image)
     return {};
 
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
index def1cc28..80b33eda 100644
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
@@ -23,7 +23,7 @@
 scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
     PaintImage image,
     ImageOrientation orientation) {
-  DCHECK(!image.GetSkImage()->isTextureBacked());
+  DCHECK(!image.IsTextureBacked());
   return UnacceleratedStaticBitmapImage::Create(std::move(image), orientation);
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
index d5a6bad..3406b92 100644
--- a/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.cc
@@ -47,7 +47,7 @@
     PaintImage image,
     ImageOrientation orientation)
     : StaticBitmapImage(orientation), paint_image_(std::move(image)) {
-  CHECK(paint_image_.GetSkImage());
+  DCHECK(paint_image_);
 }
 
 UnacceleratedStaticBitmapImage::~UnacceleratedStaticBitmapImage() {
@@ -98,7 +98,7 @@
 void UnacceleratedStaticBitmapImage::Transfer() {
   DETACH_FROM_THREAD(thread_checker_);
 
-  original_skia_image_ = paint_image_.GetSkImage();
+  original_skia_image_ = paint_image_.GetSwSkImage();
   original_skia_image_task_runner_ = Thread::Current()->GetTaskRunner();
 }
 
@@ -108,7 +108,7 @@
     SkColorType color_type) {
   DCHECK(color_space);
 
-  sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSkImage();
+  sk_sp<SkImage> skia_image = PaintImageForCurrentFrame().GetSwSkImage();
   // If we don't need to change the color type, use SkImage::makeColorSpace()
   if (skia_image->colorType() == color_type) {
     skia_image = skia_image->makeColorSpace(color_space);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.cc
index 4470630..f6b73edd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.cc
@@ -46,7 +46,7 @@
       cors_flag(false),
       parser_disposition(kParserInserted),
       cache_aware_loading_enabled(kNotCacheAwareLoadingEnabled),
-      world(std::move(world)) {}
+      world_for_csp(std::move(world)) {}
 
 ResourceLoaderOptions::ResourceLoaderOptions(
     const ResourceLoaderOptions& other) = default;
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
index d8631c9..dd4c516 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h
@@ -119,8 +119,7 @@
 
   // The world in which this request initiated. This will be used for CSP checks
   // if specified. If null, the CSP bound to the FetchContext is used.
-  // TODO(crbug.com/896041): Rename to |world_for_csp|.
-  scoped_refptr<const DOMWrapperWorld> world;
+  scoped_refptr<const DOMWrapperWorld> world_for_csp;
 
   // If not null, this URLLoaderFactory should be used to load this resource
   // rather than whatever factory the system might otherwise use.
diff --git a/third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h b/third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h
index f7f61d75..1821e68b 100644
--- a/third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h
@@ -43,8 +43,9 @@
 namespace blink {
 
 class RTCIceCandidatePlatform;
-class RTCRtpTransceiverPlatform;
 class RTCRtpReceiverPlatform;
+class RTCRtpTransceiverPlatform;
+class RTCSessionDescriptionPlatform;
 
 struct PLATFORM_EXPORT WebRTCSctpTransportSnapshot {
   rtc::scoped_refptr<webrtc::SctpTransportInterface> transport;
@@ -66,6 +67,11 @@
                                    const String& url,
                                    int error_code,
                                    const String& error_text) = 0;
+  virtual void DidChangeSessionDescriptions(
+      RTCSessionDescriptionPlatform* pending_local_description,
+      RTCSessionDescriptionPlatform* current_local_description,
+      RTCSessionDescriptionPlatform* pending_remote_description,
+      RTCSessionDescriptionPlatform* current_remote_description) = 0;
   virtual void DidChangeSignalingState(
       webrtc::PeerConnectionInterface::SignalingState) = 0;
   virtual void DidChangeIceGatheringState(
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9b30701..101a565 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -146,7 +146,6 @@
     },
     {
       name: "AllowContentInitiatedDataUrlNavigations",
-      status: "stable",
     },
     {
       name: "AllowSyncXHRInPageDismissal",
@@ -823,7 +822,9 @@
     {
       name: "FontAccess",
       origin_trial_feature_name: "FontAccess",
-      status: "experimental",
+      // No status because this blink runtime feature doesn't work by itself.
+      // It's controlled by the corresponding Chromium feature which needs to
+      // be enabled to make the whole feature work.
     },
     {
       name: "FontSrcLocalMatching",
@@ -859,7 +860,6 @@
     },
     {
       name: "FractionalScrollOffsets",
-      status: "experimental",
     },
     {
       name: "FreezeFramesOnVisibility",
@@ -1796,7 +1796,7 @@
       name: "SubresourceWebBundles",
       origin_trial_feature_name: "SubresourceWebBundles",
       origin_trial_allows_third_party: true,
-      status: "experimental"
+      status: "test"
     },
     {
       name: "SurfaceEmbeddingFeatures",
diff --git a/third_party/blink/web_tests/NeverFixTests b/third_party/blink/web_tests/NeverFixTests
index 540d055..62fcdb1 100644
--- a/third_party/blink/web_tests/NeverFixTests
+++ b/third_party/blink/web_tests/NeverFixTests
@@ -2145,10 +2145,6 @@
 # This test run under virtual suites only.
 crbug.com/1018640 external/wpt/web-bundle/wbn-from-network/* [ Skip ]
 virtual/wbn-from-network/external/wpt/web-bundle/wbn-from-network/* [ Pass ]
-crbug.com/1082020 external/wpt/web-bundle/subresource-loading/* [ Skip ]
-virtual/subresource-web-bundles/external/wpt/web-bundle/subresource-loading/* [ Pass ]
-crbug.com/1082020 http/tests/loading/wbn/subresource-loading/* [ Skip ]
-virtual/subresource-web-bundles/http/tests/loading/wbn/subresource-loading/* [ Pass ]
 crbug.com/1082020 http/tests/loading/wbn/origin-trial/* [ Skip ]
 virtual/subresource-web-bundles-disabled/http/tests/loading/wbn/origin-trial/* [ Pass ]
 
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 27c53390..f5fa8bdf 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1052,8 +1052,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-003.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-006.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-children-height-008.html [ Failure ]
-crbug.com/994172 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-007.html [ Pass Crash ]
-crbug.com/924142 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-dynamic-add-010.html [ Crash Pass ]
 crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-002.html [ Failure Crash ]
 crbug.com/874051 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-fieldset-003.html [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/external/wpt/css/css-multicol/multicol-span-all-list-item-001.html [ Failure ]
@@ -1072,8 +1070,6 @@
 crbug.com/1079031 virtual/layout_ng_block_frag/fast/multicol/abspos-new-width-rebalance.html [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/balance-float-after-forced-break.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/balance-line-overflow.html [ Failure ]
-crbug.com/994172 virtual/layout_ng_block_frag/fast/multicol/balance-line-underflow-1.html [ Pass Crash ]
-crbug.com/994172 virtual/layout_ng_block_frag/fast/multicol/balance-line-underflow-2.html [ Pass Crash ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/border-radius-clipped-layer.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/border-radius-clipped-layer-second-column.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/break-before-first-line-in-first-child.html [ Failure ]
@@ -1098,7 +1094,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/dynamic/insert-spanner-into-stf-unconstrained-width.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/dynamic/relpos-becomes-static-has-abspos.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/dynamic/remove-column-content-next-to-abspos-between-spanners.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/dynamic/remove-inline-and-spanner-after-spanner-foreignObject.html [ Pass Crash Timeout ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/dynamic/static-becomes-relpos-has-abspos.html [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/event-offset-in-nested.html [ Failure ]
 crbug.com/875235 virtual/layout_ng_block_frag/fast/multicol/fieldset-as-multicol.html [ Failure ]
@@ -1115,7 +1110,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-block.html [ Failure Timeout ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line-and-unbreakable.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/float-with-margin-moved-by-child-line.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/flowthread-with-floats-destroyed-crash.html [ Crash Pass ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/forced-break-in-nested-columns.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/forced-break-too-short-column.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/hit-test-above-or-below.html [ Failure ]
@@ -1159,7 +1153,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/float.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/inside-block-with-fixed-height.html [ Failure ]
 crbug.com/1058792 virtual/layout_ng_block_frag/fast/multicol/span/invalid-spanner-in-transform.html [ Failure Crash ]
-crbug.com/1040947 virtual/layout_ng_block_frag/fast/multicol/span/list-multi-column-crash.html [ Crash Pass ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/outer-column-break-after-inner-spanner-2.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/outer-column-break-after-inner-spanner-and-float.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/span/outer-column-break-after-inner-spanner.html [ Failure ]
@@ -1200,8 +1193,6 @@
 crbug.com/829028 virtual/layout_ng_block_frag/fast/multicol/widows.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/fragmentation/abspos-after-forced-break.html [ Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/auto-scrollbar-shrink-to-fit.html [ Failure ]
-crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/become-unfragmented-with-lines.html [ Crash Pass ]
-crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/become-unfragmented-with-unbreakable-blocks.html [ Crash Pass ]
 crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/change-fragmentainer-height-inline-float.html [ Failure ]
 crbug.com/1079031 virtual/layout_ng_block_frag/fragmentation/content-preceding-first-fragmentainer.html [ Crash Failure ]
 crbug.com/829028 virtual/layout_ng_block_frag/fragmentation/float-after-forced-break.html [ Failure ]
@@ -2568,6 +2559,8 @@
 crbug.com/1105958 external/wpt/payment-request/payment-is-showing.https.html [ Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-pseudo/selection-overlay-and-grammar-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-pseudo/selection-overlay-and-spelling-001.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/html/cross-origin-embedder-policy/reporting-subresource-corp.https.html [ Failure Timeout ]
 crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/replaced-element-016.tentative.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-sizing/aspect-ratio/replaced-element-021.tentative.html [ Failure ]
@@ -3389,23 +3382,25 @@
 crbug.com/618969 external/wpt/css/css-grid/subgrid/* [ Skip ]
 
 # [layout-ng-grid]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-layout-properties.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-tracks-stretched-with-different-flex-factors-sum.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-changing-containing-block-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-definite-sizes-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-containing-block-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/absolute-positioning-grid-container-parent-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/empty-grid-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-paint-positioned-children-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-item-dynamic-change-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/descendant-static-position-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/empty-grid-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-paint-positioned-children-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-children-writing-modes-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-item-dynamic-change-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-and-autofit-tracks-007.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-background-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-background-rtl-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-content-alignment-001.html [ Failure ]
@@ -3420,22 +3415,22 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-unknown-named-grid-line-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-positioned-items-within-grid-implicit-track-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/grid-sizing-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-015.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-descendants-016.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-003.html [ Failure ]
@@ -3453,22 +3448,22 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-016.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/orthogonal-positioned-grid-items-017.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-015.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-descendants-016.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-003.html [ Failure ]
@@ -3486,8 +3481,9 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-016.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-017.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-create-implicit-tracks-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-should-not-take-up-space-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/abspos/positioned-grid-items-sizing-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-baseline-vertical.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-baseline.html [ Failure ]
@@ -3501,7 +3497,7 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-margin-border-padding-vertical-rl.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-margin-border-padding.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-overflow.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-stretch-with-orthogonal-flows.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-stretch-with-orthogonal-flows.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-justify-stretch.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align-stretching-replaced-items.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-align.html [ Failure ]
@@ -3539,50 +3535,53 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-implies-size-change-036.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-004.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-004.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-alignment-style-changes-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-cycles-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-011.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-block-axis-alignment-auto-margins-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-011.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-012.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-013.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-014.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-positioned-items-017.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-sticky-positioned-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-alignment-sticky-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-column-axis-self-baseline-synthesized-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-container-auto-margins-scrollbars-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-container-baseline-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-alignment-and-self-alignment-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-container-baseline-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-alignment-and-self-alignment-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-alignment-and-self-alignment-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-alignment-auto-sized-tracks-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-alignment-overflow-001.html [ Failure ]
@@ -3640,7 +3639,7 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-distribution-with-collapsed-tracks-022.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-distribution-with-collapsed-tracks-023.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-content-distribution-with-collapsed-tracks-024.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-fit-content-tracks-dont-stretch-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-003.html [ Failure ]
@@ -3653,88 +3652,93 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-011.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-014.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-014.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-gutters-and-alignment.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows-vertical-lr.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows-vertical-rl.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-inline-axis-alignment-auto-margins-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows-vertical-lr.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows-vertical-rl.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-alignment-with-orthogonal-flows.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-auto-margins-alignment-vertical-lr.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-auto-margins-alignment-vertical-rl.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-auto-margins-alignment.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-1.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-2.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-3.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-4.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-5.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-6.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-7.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-8.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-9.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-item-no-aspect-ratio-stretch-10.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-place-content-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-015.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-016.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-positioned-items-017.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-sticky-positioned-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-alignment-sticky-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-004.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-004.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-row-axis-self-baseline-synthesized-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-008.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-015.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-non-static-positioned-items-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-015.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-positioned-items-with-margin-border-padding-016.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-008.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-008.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-011.html [ Failure ]
@@ -3743,15 +3747,15 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-014.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-input-range.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-input-range.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-008.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-008.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-lr-011.html [ Failure ]
@@ -3764,10 +3768,10 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-008.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-008.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-009.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-011.html [ Failure ]
@@ -3776,18 +3780,18 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-014.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-015.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-alignment-stretch-vertical-rl-016.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-003.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-self-baseline-not-applied-if-sizing-cyclic-dependency-003.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-002-b.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-008.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-008.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-003.html [ Failure ]
@@ -3797,31 +3801,37 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-007.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-008.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-changes-grid-area-size-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-006.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-horiz-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-lr-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/explicit-grid-size-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/self-baseline/grid-self-baseline-vertical-rl-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/animation/grid-template-columns-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/animation/grid-template-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/anonymous-grid-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/chrome-bug-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/chrome-crash-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-child-percent-basis-resize-1.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/explicit-grid-size-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/flex-content-distribution-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/flex-content-resolution-columns-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/flex-content-resolution-columns-002.html [ Failure ]
@@ -3831,120 +3841,172 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/flex-item-grid-container-percentage-rows-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/fr-unit-with-percentage.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/fr-unit.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fill-columns-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fill-rows-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fit-columns-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fit-rows-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-intrinsic-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-max-size-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-add-item-with-positioned-items-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-add-positioned-block-item-after-inline-item-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-explicit-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fill-columns-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fill-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fit-columns-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-fit-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-intrinsic-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-max-size-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-max-size-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-min-max-size-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-min-size-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-min-size-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-min-size-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-003.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-multiple-values-003.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-auto-repeat-positioned-container-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-auto-repeat-tracks.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-fit-content-argument-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-intrinsic-size-with-auto-repeat-tracks-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-auto-repeat-tracks.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-fit-content-argument-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-change-intrinsic-size-with-auto-repeat-tracks-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-auto-repeat-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-flexible-lengths-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-grid-template-columns-rows-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-named-grid-lines-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-repeat-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-template-columns-rows-resolved-values-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-template-columns-rows-resolved-values-001.tentative.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-flexible-lengths-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-grid-template-columns-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-named-grid-lines-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-support-repeat-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-template-columns-rows-resolved-values-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-inline-template-columns-rows-resolved-values-001.tentative.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-layout-auto-tracks.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-layout-basic.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-layout-repeat-notation.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-limits-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-layout-repeat-notation.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-limits-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-minimum-contribution-with-percentages.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-percentage-rows-indefinite-height-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-flexible-lengths-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-grid-template-columns-rows-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-repeat-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-changes-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-resolved-values-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-resolved-values-001.tentative.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/anonymous-grid-item-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-items-inline-blocks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-flexible-lengths-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-grid-template-columns-rows-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-named-grid-lines-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-repeat-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-support-repeat-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-fit-content-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-changes-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-resolved-values-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-columns-rows-resolved-values-001.tentative.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-definition/grid-template-rows-fit-content-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-item-non-auto-height-stretch-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-item-non-auto-height-stretch-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-item-non-auto-height-stretch-003.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-item-non-auto-height-stretch-004.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/anonymous-grid-item-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/explicitly-sized-grid-item-as-table.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-automatic-minimum-intrinsic-aspect-ratio-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-items-inline-blocks-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-auto-placement-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-order-property-painting-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-inline-z-axis-ordering-overlapped-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-001.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-002.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-003.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-containing-block-004.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-dynamic-min-contribution-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-flex-container-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-margins-and-writing-modes-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-min-auto-size-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-overflow-auto-max-height-percentage.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-percentage-sizes-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-inline-blocks-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-item-script-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-inline-blocks-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-height-orthogonal-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-orthogonal-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-orthogonal-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-orthogonal-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-vertical-lr-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-vertical-lr-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-vertical-rl-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-minimum-width-vertical-rl-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-lr-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-lr-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-rl-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-rl-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-007.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-lr-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-lr-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-rl-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-rl-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-lr-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-lr-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-rl-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-margins-vertical-rl-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-009.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-010.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-011.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-012.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-013.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-014.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-lr-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-lr-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-rl-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-percentage-paddings-vertical-rl-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-relative-offsets-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-relative-offsets-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-sizing-alignment-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-items-sizing-alignment-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-layout-grid-in-grid.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-layout-z-order-a.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-layout-z-order-b.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-007.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-008.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-009.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-010.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-011.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-012.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-013.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-014.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-015.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-013.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-014.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-015.html [ Pass ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-016.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-017.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-018.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-018.html [ Pass ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-019.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-020.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-021.html [ Failure ]
@@ -3952,146 +4014,220 @@
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-023.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-024.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-minimum-size-grid-items-025.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-auto-placement-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-order-property-painting-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-005.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-005.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/grid-z-axis-ordering-overlapped-items-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-replaced-subitems-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-subitems-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/whitespace-in-grid-item-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/item-with-table-with-infinite-max-intrinsic-width.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-replaced-subitems-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/percentage-size-subitems-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/remove-svg-grid-item-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/table-with-infinite-max-intrinsic-width.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-items/whitespace-in-grid-item-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-layout-properties.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/column-property-should-not-apply-on-grid-container-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/compute-intrinsic-widths-scrollbar-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/display-grid.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/display-inline-grid.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-box-sizing-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-button-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-vertical-lr-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-vertical-rl-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/fixed-width-intrinsic-width-should-exclude-scrollbar-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-004.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-006.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-007.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-areas-overflowing-grid-container-008.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-box-sizing-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-button-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-computed-value-display-floated-items-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-ignores-first-letter-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-ignores-first-letter-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-ignores-first-line-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-margin-border-padding-scrollbar-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-vertical-lr-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbar-vertical-rl-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbars-sizing-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-scrollbars-sizing-002.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-container-sizing-constraints-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-letter-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-float-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-display-grid-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-display-inline-grid-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-letter-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-letter-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-letter-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-line-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-line-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-first-line-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-float-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-float-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-floats-no-intrude-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-floats-no-intrude-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-gutters-and-flex-content-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-gutters-and-tracks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-gutters-as-percentage-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-margins-no-collapse-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-min-max-height-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-gutters-and-tracks-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-gutters-as-percentage-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-letter-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-letter-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-letter-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-line-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-line-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-first-line-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-float-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-floats-no-intrude-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-margins-no-collapse-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-inline-vertical-align-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-item-accepts-first-letter-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-item-accepts-first-line-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-layout-stale-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-margins-no-collapse-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-margins-no-collapse-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-min-max-height-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-size-shrink-to-fit-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-model/grid-vertical-align-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/grid-tracks-stretched-with-different-flex-factors-sum.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/implicit-grids/grid-support-grid-auto-columns-rows-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/implicit-grids/grid-support-grid-auto-columns-rows-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/implicit-grids/grid-support-grid-auto-columns-rows-003.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/implicit-grids/grid-support-grid-auto-columns-rows-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/auto-margins-ignored-during-track-sizing-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-005.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-006.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-sizing-columns-min-max-width-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-sizing-rows-min-max-height-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-007.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-and-intrinsic-sizes-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-sizing-columns-min-max-width-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/flex-sizing-rows-min-max-height-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-005.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-006.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-007.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-as-flex-item-should-not-shrink-to-fit-008.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-automatic-minimum-for-auto-columns-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-container-percentage-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-container-percentage-002.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-content-distribution-must-account-for-track-sizing-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-content-distribution-must-account-for-track-sizing-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-content-distribution-must-account-for-track-sizing-003.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-content-distribution-must-account-for-track-sizing-004.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-find-fr-size-gutters-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-find-fr-size-gutters-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-fit-content-percentage.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-fit-content-percentage.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-flex-track-intrinsic-sizes-003.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-size-with-orthogonal-items.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-intrinsic-track-sizes-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-lr-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-item-margin-auto-columns-rows-vertical-rl-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-layout-free-space-unit.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim-vertical-lr.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim-vertical-rl.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-stretch-respects-min-size-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-columns-computed-implicit-track.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-columns-computed-withcontent.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim-vertical-lr.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim-vertical-rl.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-minimum-contribution-baseline-shim.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-percent-cols-spanned-shrinkwrap-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-percent-cols-filled-shrinkwrap-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-percent-rows-filled-shrinkwrap-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-percent-rows-spanned-shrinkwrap-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/grid-stretch-respects-min-size-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-columns-computed-implicit-track.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-columns-computed-withcontent.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-columns-computed.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-repeat-auto-computed-withcontent-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-repeat-auto-computed-withcontent-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-repeat-auto-computed-withcontent-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-rows-computed-implicit-track.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-rows-computed-withcontent.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-rows-computed-implicit-track.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-rows-computed-withcontent.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/parsing/grid-template-rows-computed.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-auto-flow-sparse-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-auto-placement-implicit-tracks-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-container-change-grid-tracks-recompute-child-positions-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-auto-placement-implicit-tracks-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-container-change-grid-tracks-recompute-child-positions-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-container-change-named-grid-recompute-child-positions-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-grid-span.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-lines-shorthands.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-lines.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-lines-shorthands.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-lines.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-layout-placement-shorthands.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-001.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-002.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-004.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-004.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-006.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-006.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-007.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-008.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-placement-using-named-grid-lines-009.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-justify-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/alignment/grid-baseline-align-001.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/placement/grid-template-areas-must-keep-named-columns-order-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/table-grid-item-dynamic-001.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/auto-content-resolution-columns.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/auto-content-resolution-rows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/breadth-size-resolution-grid.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/calc-resolution-grid-item.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/breadth-size-resolution-grid.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/calc-resolution-grid-item.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/changing-content-property-on-nested-grid-should-not-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/containing-block-grids.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/flex-and-content-sized-resolution-columns.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/flex-and-intrinsic-sizes.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/flex-content-sized-column-use-available-width.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/flex-content-sized-columns-resize.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-columns-rows-auto-flow-resolution.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/floating-empty-grids.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-columns-rows-auto-flow-resolution.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-columns-rows-get-set.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-columns-rows-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-columns-rows-update.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-flow-get-set.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-flow-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-flow-update.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-repeat-huge-grid.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-repeat-huge-grid.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-auto-repeat-inherit-initial-crash.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-columns-rows-get-set-multiple.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-columns-rows-get-set.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-content-sized-columns-resolution.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-columns-rows-get-set.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-content-sized-columns-resolution.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-crash-out-of-flow-positioned-element.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-crash-remove-positioned-item.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-auto-repeat-get-set.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-border-grid-item.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-border-padding-grid-item.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-embed-crash.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-empty-row-column.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-min-max-width.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-padding-grid-item.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-padding-margin.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-element-repeat-get-set.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-grow-tracks-to-their-max.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-initialize-span-one-items.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-addition-auto-placement-update.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-indefinite-calculated-height-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-indefinite-size-auto-repeat-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-initialize-span-one-items.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-intrinsic-maximums.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-addition-auto-placement-update.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-addition-track-breadth-update.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-margins-and-stretch.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-margins-must-respect-specified-margins.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-automatic-span.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-definite-span.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-fixed-row-column.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-automatic-span.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-definite-span.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-placement-fixed-row-column.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-auto-sized-align-justify-margin-border-padding.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-bad-named-area-auto-placement.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-bad-resolution-double-span.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-before-anonymous-child-crash.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-border-overflow-paint.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-change-alignment-from-stretch.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-change-order-auto-flow.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-display.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-change-order-auto-flow.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-display.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-grid-container-percentage-rows.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-margin-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-multiple-minmax-content-resolution.html [ Failure ]
@@ -4101,26 +4237,30 @@
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-negative-integer-explicit-grid-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-negative-position-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-order-auto-flow-resolution.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-order-paint-order.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-order-paint-order.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-overflow-paint.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-overflow.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-overflow.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-paddings-and-writing-modes.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-position-changed-dynamic.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-positioning-with-orthogonal-flows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-removal-auto-placement-update.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-removal-track-breadth-update.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-scroll-position.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-removal-auto-placement-update.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-removal-track-breadth-update.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-scroll-position.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-sizing-with-orthogonal-flows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-spanning-and-orthogonal-flows.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-spanning-and-orthogonal-flows.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-spanning-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-stretch-with-margins-borders-padding-vertical-lr.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-stretch-with-margins-borders-padding-vertical-rl.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-stretch-with-margins-borders-padding.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-stretching-must-not-depend-on-previous-layouts.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-text-background-not-interleaved.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-unknown-named-grid-line-resolution.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-border-in-fr.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-border-in-fr.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-border-in-intrinsic.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-percent-height-in-auto-height-grid-resolution.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-percent-height-replaced-element.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-percent-height-replaced-element.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-with-percent-min-max-height-dynamic.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-item-z-index-stacking-context.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-items-should-not-be-stretched-when-height-or-width-or-margin-change.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-justify-content-distribution-vertical-lr.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-justify-content-distribution-vertical-rl.html [ Failure ]
@@ -4128,31 +4268,42 @@
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-justify-content-vertical-lr.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-justify-content-vertical-rl.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-justify-content.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-only-abspos-item-computed-style-crash.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-margins-not-collapse.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-only-abspos-item-computed-style-crash.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-painting-item-overflow.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-painting-respect-dom-order.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-painting-respect-dom-order.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-painting-rtl.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-percent-track-margin-border-padding.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-percent-track-scrollbar.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-preferred-logical-widths.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-two-dimensional.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-and-flex-tracks-with-indefinite-container-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-and-flexible-tracks-should-not-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-and-item-relayout-should-not-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-and-relative-sized-items-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-and-relative-sized-tracks-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-followed-by-item-style-change-should-not-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-self-baseline-two-dimensional.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-shorthand-get-set.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-shorthands-style-format.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-strict-ordering-crash-2.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-template-columns-rows-computed-style-gaps-content-alignment.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-template-shorthand-get-set.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-margins-and-orthogonal-flows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-orthogonal-flows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-percentages-and-orthogonal-flows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-update-sizes-after-distributing-all.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-template-shorthand-infinite-loop.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-margins-and-orthogonal-flows.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-orthogonal-flows.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-track-sizing-with-percentages-and-orthogonal-flows.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/grid-update-sizes-after-distributing-all.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/implicit-columns-auto-resolution.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/implicit-position-dynamic-change.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/implicit-rows-auto-resolution.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/implicit-tracks-before-explicit.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/justify-self-cell.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/implicit-tracks-before-explicit.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/justify-self-cell.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mark-as-infinitely-growable.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/maximize-tracks-definite-indefinite-height.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/maximize-tracks-definite-indefinite-width.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/maximize-tracks-definite-indefinite-height.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/maximize-tracks-definite-indefinite-width.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-content-row-must-shrink-when-column-grows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-height-border-box.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-width-height-auto-and-margins.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-height-border-box.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-width-height-auto-and-margins.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-width-height-auto-overflow.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-width-height-auto.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/min-width-margin-box.html [ Failure ]
@@ -4162,50 +4313,50 @@
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-max-content-resolution-rows.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-min-content-column-resolution-columns.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-min-content-column-resolution-rows.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-spanning-resolution-columns.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-spanning-resolution-rows.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-spanning-resolution-columns.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/minmax-spanning-resolution-rows.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-001.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-002.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-003.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-004.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-005-part-1.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-005-part-2.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-areas-dynamic-with-media-query.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-line-get-set.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-lines-computed-style-implicit-tracks.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-lines-computed-style-implicit-tracks.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-dynamic-get-set.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/named-grid-lines-with-named-grid-areas-resolution.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/negative-growth-share-as-infinity-crash.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/negative-growth-share-as-infinity-crash.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/non-grid-columns-rows-get-set.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/painting-item-marginbox-overflowing-grid-area.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-grid-item-in-percent-grid-track-in-percent-grid.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-grid-item-in-percent-grid-track-update.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-grid-item-in-percent-grid-track.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-intrinsic-track-breadth.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-of-indefinite-track-size-in-auto.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-of-indefinite-track-size.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-intrinsic-track-breadth.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-of-indefinite-track-size-in-auto.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-of-indefinite-track-size.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-padding-margin-resolution-grid-item-update.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-padding-margin-resolution-grid-item.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-resolution-grid-item-children.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-resolution-grid-item.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-resolution-grid-item-children.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-resolution-grid-item.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/percent-track-breadths-regarding-container-size.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/place-cell-by-index.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/positioned-grid-container-item-percentage-size.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/positioned-grid-container-item-percentage-size.html [ Pass ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/positioned-grid-container-percentage-tracks.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/preferred-width-computed-after-layout.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/quirks-mode-percent-resolution-grid-item.html [ Failure ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/preferred-width-computed-after-layout.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/quirks-mode-percent-resolution-grid-item.html [ Failure Crash ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/relayout-align-items-changed.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/relayout-align-self-changed.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/relayout-indefinite-heights.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/relayout-justify-items-changed.html [ Failure ]
 crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/relayout-justify-self-changed.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/repeating-layout-must-produce-the-same-results.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/scrolled-grid-painting-overflow.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/scrolled-grid-painting.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-005-part-1.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/mozilla/grid-repeat-auto-fill-fit-005-part-2.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-001.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-002.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-003.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-004.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-005.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/layout-algorithm/baseline-alignment-affects-intrinsic-size-006.html [ Failure ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/animation/grid-template-columns-001.html [ Pass ]
-crbug.com/1045599 virtual/layout-ng-grid/external/wpt/css/css-grid/animation/grid-template-rows-001.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/repeating-layout-must-produce-the-same-results.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/scrolled-grid-painting-overflow.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/scrolled-grid-painting.html [ Pass ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/setting-node-properties-to-null-during-layout-should-not-crash.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/should-not-collapse-anonymous-blocks.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/swap-lines-if-start-is-further-endward-than-end-line.html [ Failure Crash ]
+crbug.com/1045599 virtual/layout-ng-grid/fast/css-grid-layout/vertical-align-do-not-effect-grid-items.html [ Failure Crash ]
 
 # [css-logical]
 crbug.com/865579 external/wpt/css/css-logical/animation-001.html [ Failure Pass ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index 4b5dcc69..c8d2daf 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -724,12 +724,6 @@
     "args": [ "--enable-features=OutOfBlinkCSPEE" ]
   },
   {
-    "prefix": "subresource-web-bundles",
-    "bases": [ "external/wpt/web-bundle/subresource-loading",
-               "http/tests/loading/wbn/subresource-loading" ],
-    "args": [ "--enable-blink-features=SubresourceWebBundles" ]
-  },
-  {
     "prefix": "subresource-web-bundles-disabled",
     "bases": [ "http/tests/loading/wbn/origin-trial/" ],
     "args": [ "--disable-blink-features=SubresourceWebBundles" ]
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 7b5ace7..61426b3 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
@@ -82370,6 +82370,32 @@
        {}
       ]
      ],
+     "selection-overlay-and-grammar-001.html": [
+      "e4fe6e682e63f9382f920fbabf2126fc80640308",
+      [
+       null,
+       [
+        [
+         "/css/css-pseudo/reference/selection-overlay-and-grammar-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
+     "selection-overlay-and-spelling-001.html": [
+      "64129ab5f56b85ba901645f1128e35e27a9c64c2",
+      [
+       null,
+       [
+        [
+         "/css/css-pseudo/reference/selection-overlay-and-spelling-001-ref.html",
+         "=="
+        ]
+       ],
+       {}
+      ]
+     ],
      "selection-text-shadow-016.html": [
       "44403c1b5f5fb2bf7245c73f5eb5c15ffd19a98a",
       [
@@ -183406,6 +183432,14 @@
        "3ead305bfb8eaf08424b789f40efa73c26d8dfe3",
        []
       ],
+      "selection-overlay-and-grammar-001-ref.html": [
+       "f5a416ecef3547a3eca8749cdfc530a4fca5ced0",
+       []
+      ],
+      "selection-overlay-and-spelling-001-ref.html": [
+       "5dffca9f358026645bc6f8fdd0cf145250fd05bd",
+       []
+      ],
       "selection-textarea-011-ref.html": [
        "825a4247a202dac2bc3dde257ddff81f2e8eded8",
        []
@@ -239841,7 +239875,7 @@
        []
       ],
       "conftest.py": [
-       "dffae0b98cd67c664883f4e4efd608415c82b179",
+       "5ee8ae1c741a9c75658d36d774e0c2523913c6d5",
        []
       ],
       "support": {
@@ -323928,7 +323962,7 @@
          ]
         ],
         "canvas-createPutGetImageData-colorManaged.html": [
-         "a6b202e8f2bd671ce5074146d127abf6d2baf910",
+         "f153a983d93d5ee33893fd23340dfcc5b26e098a",
          [
           null,
           {}
@@ -323956,21 +323990,14 @@
          ]
         ],
         "canvas-getImageData-e_srgb.html": [
-         "f5f0e629dd19f4d65531b15bf39595e587ded974",
+         "c38da7c95c0d48fd009c9073697f0232379918f9",
          [
           null,
           {}
          ]
         ],
         "imageData-colorManagedBehavior.html": [
-         "6bc55b7ca70e9cc0fe28e4e0f27a5e094fd725cb",
-         [
-          null,
-          {}
-         ]
-        ],
-        "imageData-colorSpace.html": [
-         "9023cbea3620686b04aeed15120284bdf9a41478",
+         "dda9f9cc28f051114f21b27fe470aafe1ce2b06e",
          [
           null,
           {}
@@ -427005,7 +427032,7 @@
        ]
       ],
       "pointer.py": [
-       "d021eee7c9404cf09194a41632b6093c72ce961d",
+       "fcb1e5b1bf0014ad66d6bedc40a0c2986a96519c",
        [
         null,
         {
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-grammar-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-grammar-001-ref.html
new file mode 100644
index 0000000..f5a416e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-grammar-001-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE html>
+
+ <html lang="en">
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reftest Reference</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-size: 60px;
+      line-height: 90px;
+    }
+
+  div#overlapped-line
+    {
+      color: transparent;
+      margin-bottom: -90px;
+    }
+
+  span#single-word
+    {
+      background-color: yellow;
+    }
+
+  span#overlapping-line
+    {
+      background-color: rgba(0%, 50%, 100%, 0.5);
+      /*
+      a very lite blue color
+      according to
+      https://www.colorhexa.com/7fbfff
+      */
+      color: yellow;
+    }
+  </style>
+
+  <script>
+  function startTest()
+  {
+  document.getElementById("reference").blur();
+  /*
+  Some browsers, like Chromium 80+, will
+  transfer focus to a selected element
+  like a contenteditable div and
+  therefore style the border of
+  such element. We remove such
+  focus with the blur() method.
+  */
+  }
+  </script>
+
+  <body onload="startTest();">
+
+  <p>PREREQUISITE: User agent needs to have an enabled and capable grammar error module. If it does not, then this test does not apply to such user agent.
+
+  <p>Test passes
+
+  <ul>
+    <li>if each glyph of the sentence is yellow
+    <li>if "thing" has a desaturated lime green background
+    <li>if the other words have a very lite blue background and
+    <li>if there is no red.
+  </ul>
+
+  <div id="overlapped-line">Many <span id="single-word">thing</span> can happen.</div>
+
+  <div contenteditable="true"><span id="overlapping-line">Many thing can happen.</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-spelling-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-spelling-001-ref.html
new file mode 100644
index 0000000..5dffca9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/reference/selection-overlay-and-spelling-001-ref.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+ <html lang="en">
+
+  <meta charset="UTF-8">
+
+  <title>CSS Reftest Reference</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+
+  <style>
+  div
+    {
+      font-size: 60px;
+      line-height: 1;
+    }
+
+  span#outer
+    {
+      color: transparent;
+    }
+
+  span#inner
+    {
+      background-color: yellow;
+    }
+
+  div#overlapping-line
+    {
+      margin-top: -60px; /* -1lh unfortunately is not implemented */
+    }
+
+  div#overlapping-line > span
+    {
+      background-color: rgba(0%, 50%, 100%, 0.5);
+      /*
+      a very lite blue color
+      according to
+      https://www.colorhexa.com/7fbfff
+      */
+      color: yellow;
+    }
+  </style>
+
+  <p>PREREQUISITE: User agent needs to have an enabled and capable spelling error module. If it does not, then this test does not apply to such user agent.
+
+  <p>Test passes
+
+  <ul>
+    <li>if each glyph of "Txet sample" is yellow
+    <li>if "Txet" has a desaturated lime green background
+    <li>if " sample" has a very lite blue background and
+    <li>if there is no red.
+  </ul>
+
+  <!--
+  The bad spelling of Txet is intentional and part of this test
+  -->
+
+  <div id="overlapped-line"><span id="outer"><span id="inner">Txet</span> sample</span></div>
+
+  <div id="overlapping-line"><span>Txet sample</span></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-grammar-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-grammar-001.html
new file mode 100644
index 0000000..e4fe6e6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-grammar-001.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+
+ <html lang="en">
+
+  <meta charset="UTF-8">
+
+  <title>CSS Pseudo-Elements Test: ::selection overlay drawn over the ::grammar-error overlay</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-pseudo-4/#highlight-painting">
+  <link rel="match" href="reference/selection-overlay-and-grammar-001-ref.html">
+
+  <meta content="" name="flags">
+  <meta name="assert" content="In this test, the div::selection pseudo-element must be drawn over the div::grammar-error overlay.">
+
+  <!--
+
+  The initial version of this test was relying on color
+  composition and was predicting a lime-green-ish (#7FBF80:
+  slightly desaturated lime green) background color for "thing".
+
+  "#7fbf80 color description : Slightly desaturated lime green"
+  https://www.colorhexa.com/7fbf80
+
+  This test does not rely on color composition but the
+  test nevertheless verifies the ::selection overlay drawn
+  over the ::grammar-error overlay.
+
+  -->
+
+  <style>
+  div
+    {
+      font-size: 60px;
+      line-height: 90px;
+    }
+
+  div::selection
+    {
+      background-color: rgba(0%, 50%, 100%, 0.5);
+      /*
+      a very lite blue color
+      according to
+      https://www.colorhexa.com/7fbfff
+      */
+      color: yellow;
+    }
+
+  div::grammar-error
+    {
+      background-color: yellow;
+      color: red;
+    }
+  </style>
+
+  <script>
+  function startTest()
+  {
+  var targetRange = document.createRange();
+  /* We first create an empty range */
+  targetRange.selectNodeContents(document.getElementById("test"));
+  /* Then we set the range boundaries to the children of div#test */
+  window.getSelection().addRange(targetRange);
+  /* Finally, we now select such range of content */
+  document.getElementById("test").blur();
+  /*
+  Some browsers, like Chromium 80+, will
+  transfer focus to a selected element
+  like a contenteditable div and
+  therefore style the border of
+  such element. We remove such
+  focus with the blur() method.
+  */
+  }
+  </script>
+
+  <body onload="startTest();">
+
+  <p>PREREQUISITE: User agent needs to have an enabled and capable grammar error module. If it does not, then this test does not apply to such user agent.
+
+  <p>Test passes
+
+  <ul>
+    <li>if each glyph of the sentence is yellow
+    <li>if "thing" has a desaturated lime green background
+    <li>if the other words have a very lite blue background and
+    <li>if there is no red.
+  </ul>
+
+  <div contenteditable="true" id="test">Many thing can happen.</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-spelling-001.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-spelling-001.html
new file mode 100644
index 0000000..64129ab5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/selection-overlay-and-spelling-001.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+
+ <html lang="en">
+
+  <meta charset="UTF-8">
+
+  <title>CSS Pseudo-Elements Test: ::selection overlay drawn over the ::spelling-error overlay</title>
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-pseudo-4/#highlight-painting">
+  <link rel="match" href="reference/selection-overlay-and-spelling-001-ref.html">
+
+  <meta content="" name="flags">
+  <meta name="assert" content="In this test, the div::selection pseudo-element must be drawn over the div::spelling-error overlay.">
+
+  <!--
+
+  The initial version of this test was relying on color
+  composition and was predicting a lime-green-ish (#7FBF80:
+  slightly desaturated lime green) background color for "Txet".
+
+  "#7fbf80 color description : Slightly desaturated lime green"
+  https://www.colorhexa.com/7fbf80
+
+  This test does not rely on color composition but the
+  test nevertheless verifies the ::selection overlay drawn
+  over the ::grammar-error overlay.
+
+  Chromium 83+'s selection highlight will vertically
+  extend to line box top and bottom... which is
+  under an eventual discussion in
+  https://github.com/w3c/csswg-drafts/issues/5395
+  One easy way to work around this issue
+  would be to set 'line-height' to '1' instead of
+  '90px'.
+
+  -->
+
+  <style>
+  div
+    {
+      font-size: 60px;
+      line-height: 1;
+      /*
+      We deliberately set line-height to 1 in order
+      to avoid/work around a possible difference
+      of rendering of highlight overlay among browsers.
+      In Chrome 80+, the selection highlight
+      overlay will extent vertically to include line
+      box top and line box bottom. This is not
+      the case in Firefox 68+.
+      */
+    }
+
+  div::selection
+    {
+      background-color: rgba(0%, 50%, 100%, 0.5);
+      /*
+      a very lite blue color
+      according to
+      https://www.colorhexa.com/7fbfff
+      */
+      color: yellow;
+    }
+
+  div::spelling-error
+    {
+      background-color: yellow;
+      color: red;
+    }
+  </style>
+
+  <script>
+  function startTest()
+  {
+  var targetRange = document.createRange();
+  /* We first create an empty range */
+  targetRange.selectNodeContents(document.getElementById("test"));
+  /* Then we set the range boundaries to the children of div#test */
+  window.getSelection().addRange(targetRange);
+  /* Finally, we now select such range of content */
+  }
+  </script>
+
+  <body onload="startTest();">
+
+  <p>PREREQUISITE: User agent needs to have an enabled and capable spelling error module. If it does not, then this test does not apply to such user agent.
+
+  <p>Test passes
+
+  <ul>
+    <li>if each glyph of "Txet sample" is yellow
+    <li>if "Txet" has a desaturated lime green background
+    <li>if " sample" has a very lite blue background and
+    <li>if there is no red.
+  </ul>
+
+  <!--
+  The bad spelling of Txet is intentional and part of this test
+  -->
+
+  <div id="test">Txet sample</div>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-description-attributes-timing.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-description-attributes-timing.https.html
new file mode 100644
index 0000000..2d2565c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-description-attributes-timing.https.html
@@ -0,0 +1,81 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+  const pc = new RTCPeerConnection();
+  t.add_cleanup(() => pc.close());
+  const offer = await pc.createOffer();
+
+  assert_equals(pc.pendingLocalDescription, null,
+                'pendingLocalDescription is null before setLocalDescription');
+  const promise = pc.setLocalDescription(offer);
+  assert_equals(pc.pendingLocalDescription, null,
+                'pendingLocalDescription is still null while promise pending');
+  await promise;
+  assert_not_equals(pc.pendingLocalDescription, null,
+                    'pendingLocalDescription is not null after await');
+}, "pendingLocalDescription is surfaced at the right time");
+
+promise_test(async t => {
+  const pc = new RTCPeerConnection();
+  t.add_cleanup(() => pc.close());
+  const offer = await pc.createOffer();
+
+  assert_equals(pc.pendingRemoteDescription, null,
+                'pendingRemoteDescription is null before setRemoteDescription');
+  const promise = pc.setRemoteDescription(offer);
+  assert_equals(pc.pendingRemoteDescription, null,
+                'pendingRemoteDescription is still null while promise pending');
+  await promise;
+  assert_not_equals(pc.pendingRemoteDescription, null,
+                    'pendingRemoteDescription is not null after await');
+}, "pendingRemoteDescription is surfaced at the right time");
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  const offer = await pc1.createOffer();
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+  const answer = await pc2.createAnswer();
+
+  assert_equals(pc2.currentLocalDescription, null,
+                'currentLocalDescription is null before setLocalDescription');
+  const promise = pc2.setLocalDescription(answer);
+  assert_equals(pc2.currentLocalDescription, null,
+                'currentLocalDescription is still null while promise pending');
+  await promise;
+  assert_not_equals(pc2.currentLocalDescription, null,
+                    'currentLocalDescription is not null after await');
+}, "currentLocalDescription is surfaced at the right time");
+
+promise_test(async t => {
+  const pc1 = new RTCPeerConnection();
+  t.add_cleanup(() => pc1.close());
+  const pc2 = new RTCPeerConnection();
+  t.add_cleanup(() => pc2.close());
+
+  const offer = await pc1.createOffer();
+  await pc1.setLocalDescription(offer);
+  await pc2.setRemoteDescription(offer);
+  const answer = await pc2.createAnswer();
+
+  assert_equals(pc1.currentRemoteDescription, null,
+                'currentRemoteDescription is null before setRemoteDescription');
+  const promise = pc1.setRemoteDescription(answer);
+  assert_equals(pc1.currentRemoteDescription, null,
+                'currentRemoteDescription is still null while promise pending');
+  await promise;
+  assert_not_equals(pc1.currentRemoteDescription, null,
+                    'currentRemoteDescription is not null after await');
+}, "currentRemoteDescription is surfaced at the right time");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
index 550acfb..bbb4460 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
@@ -5,6 +5,6 @@
 FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: stable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13
 FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: have-local-offer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13
 PASS Setting previously generated answer after a call to createOffer should work
-FAIL setLocalDescription(answer) should update internal state with a queued task, in the right order assert_not_equals: pendingRemoteDescription should not be set synchronously after a call to sLD got disallowed value null
+PASS setLocalDescription(answer) should update internal state with a queued task, in the right order
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
index 1608296c..cf9f74e 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
@@ -6,6 +6,6 @@
 PASS Creating and setting offer multiple times should succeed
 PASS Setting previously generated offer after a call to createAnswer should work
 PASS Negotiation works when there has been a repeated setLocalDescription(offer)
-FAIL setLocalDescription(offer) should update internal state with a queued task, in the right order assert_equals: pendingRemoteDescription should never be set due to sLD expected null but got object "[object RTCSessionDescription]"
+PASS setLocalDescription(offer) should update internal state with a queued task, in the right order
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt
deleted file mode 100644
index b0e9cd08..0000000
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-rollback-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS setLocalDescription(rollback) from have-local-offer state should reset back to stable state
-PASS setLocalDescription(rollback) from stable state should reject with InvalidStateError
-PASS setLocalDescription(rollback) after setting answer description should reject with InvalidStateError
-PASS setLocalDescription(rollback) should ignore invalid sdp content and succeed
-FAIL setLocalDescription(rollback) should update internal state with a queued tassk, in the right order assert_not_equals: pendingLocalDescription should not be set synchronously after a call to sLD got disallowed value null
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.html b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.html
new file mode 100644
index 0000000..4e6d929
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+</html>
+
+                                                                                                  
\ No newline at end of file
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.js
new file mode 100644
index 0000000..3a07350
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-fetch.js
@@ -0,0 +1,4 @@
+self.addEventListener('fetch', fetchEvent => {
+  console.log(fetchEvent); // Should pause here.
+  fetchEvent.respondWith(fetch(fetchEvent.request));
+});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks-expected.txt
new file mode 100644
index 0000000..9baa5028
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks-expected.txt
@@ -0,0 +1,27 @@
+Async stack trace for service worker fetch.
+Navigated, registering service worker
+
+Service worker activated, reloading
+
+Reloaded, continue
+enable debug header: {
+    id : <number>
+    result : {
+    }
+    sessionId : <string>
+}
+
+Evaluate:
+
+      debugger;
+      fetch("foo.json");
+      //# sourceURL=test.js
+
+Paused in page, step over
+Run stepInto with breakOnAsyncCall flag
+
+Paused in service worker
+(anonymous) at http://127.0.0.1:8000/inspector-protocol/service-worker/resources/service-worker-fetch.js:1:2
+--network request--
+(anonymous) at test.js:2:6
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js
new file mode 100644
index 0000000..1f8db87
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/service-worker-fetch-async-stacks.js
@@ -0,0 +1,64 @@
+(async function(testRunner) {
+  var {page, session, dp} =
+      await testRunner.startBlank('Async stack trace for service worker fetch.');
+
+  let swdp;
+  let swDebuggerId;
+
+  await dp.Target.setAutoAttach({autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
+  const onAttached = async event => {
+    swdp = session.createChild(event.params.sessionId).protocol;
+    swDebuggerId = (await swdp.Debugger.enable()).result.debuggerId;
+    await swdp.Debugger.setAsyncCallStackDepth({maxDepth: 32});
+    swdp.Runtime.runIfWaitingForDebugger();
+  };
+  dp.Target.onAttachedToTarget(onAttached);
+
+  await dp.ServiceWorker.enable();
+  await session.navigate('resources/service-worker-fetch.html');
+  testRunner.log('Navigated, registering service worker');
+  session.evaluateAsync(`navigator.serviceWorker.register('service-worker-fetch.js')`);
+
+  async function waitForServiceWorkerActivation() {
+    let versions;
+    do {
+      const result = await dp.ServiceWorker.onceWorkerVersionUpdated();
+      versions = result.params.versions;
+    } while (!versions.length || versions[0].status !== "activated");
+    return versions[0].registrationId;
+  }
+
+  await waitForServiceWorkerActivation();
+  testRunner.log('\nService worker activated, reloading');
+  dp.Page.reload();
+  await dp.Page.onceLifecycleEvent(event => event.params.name === 'load');
+  testRunner.log('\nReloaded, continue');
+
+  const pageDebuggerId = (await dp.Debugger.enable()).result.debuggerId;
+  await dp.Debugger.setAsyncCallStackDepth({maxDepth: 32});
+  await dp.Network.enable();
+  testRunner.log(await dp.Network.setAttachDebugHeader({enabled: true}), 'enable debug header: ');
+
+  const code = `
+      debugger;
+      fetch("foo.json");
+      //# sourceURL=test.js`;
+  testRunner.log('\nEvaluate:\n' + code);
+  session.evaluate(code);
+
+  await dp.Debugger.oncePaused();
+  testRunner.log('\nPaused in page, step over');
+  dp.Debugger.stepOver();
+
+  await dp.Debugger.oncePaused();
+  testRunner.log('Run stepInto with breakOnAsyncCall flag');
+  dp.Debugger.stepInto({breakOnAsyncCall: true});
+
+  const {callFrames, asyncStackTrace, asyncStackTraceId} = (await swdp.Debugger.oncePaused()).params;
+  testRunner.log('\nPaused in service worker');
+  await testRunner.logStackTrace(
+      new Map([[swDebuggerId, swdp.Debugger], [pageDebuggerId, dp.Debugger]]),
+      {callFrames, parent: asyncStackTrace, parentId: asyncStackTraceId},
+      swDebuggerId);
+  testRunner.completeTest();
+})
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
index 1afe0b8..293d3e2 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-properties-as-js-properties-expected.txt
@@ -440,7 +440,6 @@
 webkitFlexShrink
 webkitFlexWrap
 webkitFontFeatureSettings
-webkitFontSizeDelta
 webkitFontSmoothing
 webkitHighlight
 webkitHyphenateCharacter
diff --git a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
index 3dd7f98..93ab7dfa 100644
--- a/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
+++ b/third_party/blink/web_tests/virtual/stable/webexposed/css-property-listing-expected.txt
@@ -14,7 +14,6 @@
     -webkit-box-orient
     -webkit-box-pack
     -webkit-box-reflect
-    -webkit-font-size-delta
     -webkit-font-smoothing
     -webkit-highlight
     -webkit-hyphenate-character
diff --git a/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md b/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md
deleted file mode 100644
index 3b5ab6f..0000000
--- a/third_party/blink/web_tests/virtual/subresource-web-bundles/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This directory is for testing the SubresourceWebBundles feature.
diff --git a/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresource-loading/README.txt b/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresource-loading/README.txt
deleted file mode 100644
index 3b5ab6f..0000000
--- a/third_party/blink/web_tests/virtual/subresource-web-bundles/external/wpt/web-bundle/subresource-loading/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-This directory is for testing the SubresourceWebBundles feature.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
index 6a545e1..72c9b807 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt
@@ -5,6 +5,6 @@
 FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: stable" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13
 FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError promise_rejects_dom: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: have-local-offer" that is not a DOMException InvalidModificationError: property "code" is equal to 0, expected 13
 FAIL Setting previously generated answer after a call to createOffer should work promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Rollback not supported in Plan B"
-FAIL setLocalDescription(answer) should update internal state with a queued task, in the right order assert_not_equals: pendingRemoteDescription should not be set synchronously after a call to sLD got disallowed value null
+PASS setLocalDescription(answer) should update internal state with a queued task, in the right order
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
index 708aba1..2b750bc 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt
@@ -6,6 +6,6 @@
 PASS Creating and setting offer multiple times should succeed
 FAIL Setting previously generated offer after a call to createAnswer should work promise_test: Unhandled rejection with value: object "OperationError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Rollback not supported in Plan B"
 FAIL Negotiation works when there has been a repeated setLocalDescription(offer) assert_equals: expected 1 but got 0
-FAIL setLocalDescription(offer) should update internal state with a queued task, in the right order assert_equals: pendingRemoteDescription should never be set due to sLD expected null but got object "[object RTCSessionDescription]"
+PASS setLocalDescription(offer) should update internal state with a queued task, in the right order
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
index 7168e5b0..adfd1e2b 100644
--- a/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/blink/web_tests/webexposed/css-properties-as-js-properties-expected.txt
@@ -479,7 +479,6 @@
 webkitFlexShrink
 webkitFlexWrap
 webkitFontFeatureSettings
-webkitFontSizeDelta
 webkitFontSmoothing
 webkitHighlight
 webkitHyphenateCharacter
diff --git a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
index 83b686e4..8648950 100644
--- a/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/css-property-listing-expected.txt
@@ -14,7 +14,6 @@
     -webkit-box-orient
     -webkit-box-pack
     -webkit-box-reflect
-    -webkit-font-size-delta
     -webkit-font-smoothing
     -webkit-highlight
     -webkit-hyphenate-character
diff --git a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
index dd2a5e6..01e20173 100644
--- a/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/element-instance-property-listing-expected.txt
@@ -790,6 +790,7 @@
     property referrerPolicy
     property rel
     property relList
+    property resources
     property rev
     property sheet
     property sizes
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index c6664fb2..c401d47 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -3623,6 +3623,7 @@
     getter referrerPolicy
     getter rel
     getter relList
+    getter resources
     getter rev
     getter sheet
     getter sizes
@@ -3643,6 +3644,7 @@
     setter referrerPolicy
     setter rel
     setter relList
+    setter resources
     setter rev
     setter sizes
     setter target
diff --git a/tools/grit/PRESUBMIT.py b/tools/grit/PRESUBMIT.py
index 03b7188..7658aa2 100644
--- a/tools/grit/PRESUBMIT.py
+++ b/tools/grit/PRESUBMIT.py
@@ -10,8 +10,12 @@
 
 
 def RunUnittests(input_api, output_api):
-  return input_api.canned_checks.RunUnitTests(input_api, output_api,
-      [input_api.os_path.join('grit', 'test_suite_all.py')])
+  presubmit_path = input_api.PresubmitLocalPath()
+  return input_api.canned_checks.RunUnitTests(input_api, output_api, [
+      input_api.os_path.join('grit', 'test_suite_all.py'),
+      input_api.os_path.join(input_api.PresubmitLocalPath(),
+                             'preprocess_grit_test.py')
+  ])
 
 
 def CheckChangeOnUpload(input_api, output_api):
diff --git a/tools/grit/preprocess_grit.gni b/tools/grit/preprocess_grit.gni
new file mode 100644
index 0000000..c70221bf
--- /dev/null
+++ b/tools/grit/preprocess_grit.gni
@@ -0,0 +1,30 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//tools/grit/grit_defines.gni")
+
+template("preprocess_grit") {
+  action(target_name) {
+    script = "//tools/grit/preprocess_grit.py"
+
+    if (defined(invoker.deps)) {
+      deps = invoker.deps
+    }
+
+    inputs = []
+    outputs = []
+    foreach(in_file, invoker.in_files) {
+      inputs += [ invoker.in_folder + "/" + in_file ]
+      outputs += [ invoker.out_folder + "/" + in_file ]
+    }
+
+    args = [
+             "--in-folder",
+             rebase_path(invoker.in_folder, root_build_dir),
+             "--out-folder",
+             rebase_path(invoker.out_folder, root_build_dir),
+             "--in-files",
+           ] + invoker.in_files + grit_defines
+  }
+}
diff --git a/tools/grit/preprocess_grit.py b/tools/grit/preprocess_grit.py
new file mode 100644
index 0000000..f249359
--- /dev/null
+++ b/tools/grit/preprocess_grit.py
@@ -0,0 +1,88 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import errno
+import io
+import os
+import sys
+
+import grit.format.html_inline
+import grit.node.base
+import grit.util
+
+_CWD = os.getcwd()
+
+
+class PreprocessNode(grit.node.base.Node):
+  def __init__(self):
+    super(PreprocessNode, self).__init__()
+
+  def ProcessFile(self, filepath):
+    return grit.format.html_inline.InlineToString(
+        filepath,
+        self,
+        preprocess_only=True,
+        allow_external_script=False,
+        strip_whitespace=False,
+        rewrite_function=None,
+        filename_expansion_function=None)
+
+  def EvaluateCondition(self, expr):
+    return grit.node.base.Node.EvaluateExpression(expr, self.defines,
+                                                  self.target_platform, {})
+
+  def SetDefines(self, defines):
+    self.defines = defines
+
+  def SetTargetPlatform(self, target_platform):
+    self.target_platform = target_platform
+
+  @staticmethod
+  def Construct(defines, target_platform):
+    node = PreprocessNode()
+    node.SetDefines(defines)
+    node.SetTargetPlatform(target_platform or sys.platform)
+    return node
+
+
+def main(argv):
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--in-folder', required=True)
+  parser.add_argument('--out-folder', required=True)
+  parser.add_argument('--in-files', required=True, nargs="*")
+  parser.add_argument('-D', '--defines', nargs="*", action='append')
+  parser.add_argument('-E', '--environment')
+  parser.add_argument('-t', '--target')
+  args = parser.parse_args(argv)
+
+  in_folder = os.path.normpath(os.path.join(_CWD, args.in_folder))
+  out_folder = os.path.normpath(os.path.join(_CWD, args.out_folder))
+
+  defines = {}
+  for define_arg in args.defines:
+    define, = define_arg
+    name, val = grit.util.ParseDefine(define)
+    defines[name] = val
+
+  node = PreprocessNode.Construct(defines, args.target)
+  for input_file in args.in_files:
+    output = node.ProcessFile(os.path.join(in_folder, input_file))
+
+    out_path = os.path.join(out_folder, input_file)
+    out_dir = os.path.dirname(out_path)
+    try:
+      os.makedirs(out_dir)
+    except OSError as e:
+      # Ignore directory exists errors. This can happen if two build rules
+      # for overlapping directories hit the makedirs line at the same time.
+      if e.errno != errno.EEXIST:
+        raise
+    with io.open(out_path, mode='wb') as f:
+      f.write(output.encode('utf-8'))
+  return
+
+
+if __name__ == '__main__':
+  main(sys.argv[1:])
diff --git a/tools/grit/preprocess_grit_test.py b/tools/grit/preprocess_grit_test.py
new file mode 100644
index 0000000..d0743d4
--- /dev/null
+++ b/tools/grit/preprocess_grit_test.py
@@ -0,0 +1,49 @@
+# Copyright 2020 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import tempfile
+import unittest
+
+import preprocess_grit
+
+_HERE_DIR = os.path.dirname(__file__)
+
+
+class PreprocessGritTest(unittest.TestCase):
+  def setUp(self):
+    self._out_folder = None
+
+  def tearDown(self):
+    if self._out_folder:
+      shutil.rmtree(self._out_folder)
+
+  def _read_out_file(self, file_name):
+    assert self._out_folder
+    return open(os.path.join(self._out_folder, file_name), 'r').read()
+
+  def _run_test(self, defines, file_name):
+    assert not self._out_folder
+    self._out_folder = tempfile.mkdtemp(dir=_HERE_DIR)
+    preprocess_grit.main([
+        '--in-folder',
+        os.path.join(_HERE_DIR, 'preprocess_tests'),
+        '--out-folder',
+        self._out_folder,
+        '--in-files',
+        file_name,
+    ] + defines)
+
+  def testPreprocess(self):
+    self._run_test(['-D', 'foo', '-D', 'bar'], 'test_with_ifexpr.js')
+    actual = self._read_out_file('test_with_ifexpr.js')
+    self.assertIn('I should be included in HTML', actual)
+    self.assertIn('I should be included in JS', actual)
+    self.assertNotIn('I should be excluded from HTML', actual)
+    self.assertNotIn('I should be excluded from JS', actual)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/tools/grit/preprocess_tests/test_with_ifexpr.js b/tools/grit/preprocess_tests/test_with_ifexpr.js
new file mode 100644
index 0000000..f4da4a6
--- /dev/null
+++ b/tools/grit/preprocess_tests/test_with_ifexpr.js
@@ -0,0 +1,21 @@
+Polymer({
+  is: 'cr-foo',
+
+  _template: html`
+    <if expr="bar">
+      <button on-click="onClick_">I should be included in HTML</button>
+    </if>
+    <if expr="apple">
+      <div>I should be excluded from HTML</div>
+    </if>
+  `,
+
+  onClick_() {
+    // <if expr="orange">
+    console.log('I should be excluded from JS');
+    // </if>
+    // <if expr="foo">
+    console.log('I should be included in JS');
+    // </if>
+  }
+});
diff --git a/tools/gritsettings/resource_ids.spec b/tools/gritsettings/resource_ids.spec
index 0818d69..b3a2d309 100644
--- a/tools/gritsettings/resource_ids.spec
+++ b/tools/gritsettings/resource_ids.spec
@@ -156,6 +156,12 @@
   "chrome/browser/resources/nearby_share/nearby_share_dialog_resources.grd": {
     "includes": [1640],
   },
+  "chrome/browser/resources/nearby_share/shared/nearby_shared_resources.grd": {
+    "includes": [1645],
+  },
+  "chrome/browser/resources/nearby_share/shared/nearby_shared_resources_v3.grd": {
+    "includes": [1650],
+  },
   "chrome/browser/resources/new_tab_page/new_tab_page_resources_vulcanized.grd": {
     "includes": [1660],
   },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0fbc9bd..a45e898 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -42741,6 +42741,7 @@
   <int value="413081240" label="enable-new-md-input-view"/>
   <int value="413695227" label="NTPSuggestionsStandaloneUI:enabled"/>
   <int value="414114078" label="LitePageServerPreviews:disabled"/>
+  <int value="414937629" label="MediaNotificationsCounter:enabled"/>
   <int value="415154056" label="enable-physical-keyboard-autocorrect"/>
   <int value="415395210" label="TrimOnMemoryPressure:enabled"/>
   <int value="416691040" label="SendTabToSelfOmniboxSendingAnimation:disabled"/>
@@ -44077,6 +44078,7 @@
   <int value="1827369558" label="AndroidPayIntegrationV1:disabled"/>
   <int value="1828660283" label="enable-webfonts-intervention-trigger"/>
   <int value="1830460973" label="disable-network-settings-config"/>
+  <int value="1831103529" label="MediaNotificationsCounter:disabled"/>
   <int value="1831545645" label="query-tiles-single-tier"/>
   <int value="1831593339" label="stop-in-background:disabled"/>
   <int value="1831835753" label="MaterialDesignIncognitoNTP:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index aa766ac..a095a40 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -76241,6 +76241,16 @@
   </summary>
 </histogram>
 
+<histogram name="LiteVideo.LiteVideoDecider.OptGuideHintCacheSize"
+    units="count" expires_after="M90">
+  <owner>mcrouse@chromium.org</owner>
+  <owner>rajendrant@chromium.org</owner>
+  <summary>
+    Records the total number of LiteVideoHints, keyed by host, cached locally by
+    the LiteVideoDecider for use when queried by subframes.
+  </summary>
+</histogram>
+
 <histogram name="LiteVideo.OriginHints.ParseResult" enum="BooleanSuccess"
     expires_after="M90">
   <owner>mcrouse@chromium.org</owner>
@@ -117632,7 +117642,7 @@
 </histogram>
 
 <histogram name="Omnibox.ClipboardSuggestionRemovedAge" units="ms"
-    expires_after="2020-09-01">
+    expires_after="2021-03-01">
   <owner>gangwu@chromium.org</owner>
   <owner>fgorski@chromium.org</owner>
   <summary>
@@ -210822,6 +210832,9 @@
       Removed in M84.
     </obsolete>
   </suffix>
+  <suffix name="LiteVideo"
+      label="Provides information on how to throttle media requests to reduce
+             the adaptive bit rates of media streams."/>
   <suffix name="LoadingPredictor"
       label="Provides information about subresources predicted to be on the
              page"/>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index b1770fc..79344fe 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/ef0fb4c2707e07b2cdff4186893bceea3ab1153c/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "be6a7ab2c70ff31ad87286fee6617d97b436a541",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/0fdfdcf61cd436faf7cf9b8be2596df9c6ca6010/trace_processor_shell"
+            "hash": "4a318e434590be8c4a5d7bb2fea5ce2411353104",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/ced41e1f394dc71e63fd979d50c2fe0e507f2fbe/trace_processor_shell"
         },
         "linux": {
-            "hash": "6cf2b33261fa3274f1c8b56085b924410037460c",
-            "remote_path": "perfetto_binaries/trace_processor_shell/linux/14a9bffb3e9e43f056b7621402572b205ac1d176/trace_processor_shell"
+            "hash": "a20c495e1e27fab6701fbb22250239da65afc8e5",
+            "remote_path": "perfetto_binaries/trace_processor_shell/linux/ced41e1f394dc71e63fd979d50c2fe0e507f2fbe/trace_processor_shell"
         }
     },
     "power_profile.sql": {
diff --git a/ui/accessibility/ax_event_generator.cc b/ui/accessibility/ax_event_generator.cc
index 4197ddb..26aa1dc 100644
--- a/ui/accessibility/ax_event_generator.cc
+++ b/ui/accessibility/ax_event_generator.cc
@@ -60,7 +60,27 @@
   RemoveEvent(node_events, AXEventGenerator::Event::CHILDREN_CHANGED);
   RemoveEvent(node_events, AXEventGenerator::Event::DESCRIPTION_CHANGED);
   RemoveEvent(node_events, AXEventGenerator::Event::NAME_CHANGED);
+  RemoveEvent(node_events, AXEventGenerator::Event::OBJECT_ATTRIBUTE_CHANGED);
+  RemoveEvent(node_events, AXEventGenerator::Event::SORT_CHANGED);
   RemoveEvent(node_events, AXEventGenerator::Event::TEXT_ATTRIBUTE_CHANGED);
+  RemoveEvent(node_events,
+              AXEventGenerator::Event::WIN_IACCESSIBLE_STATE_CHANGED);
+}
+
+// Add a particular AXEventGenerator::IgnoredChangedState to
+// |ignored_changed_states|.
+void AddIgnoredChangedState(
+    AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
+    AXEventGenerator::IgnoredChangedState state) {
+  ignored_changed_states.set(static_cast<size_t>(state));
+}
+
+// Returns true if |ignored_changed_states| contains a particular
+// AXEventGenerator::IgnoredChangedState.
+bool HasIgnoredChangedState(
+    AXEventGenerator::IgnoredChangedStatesBitset& ignored_changed_states,
+    AXEventGenerator::IgnoredChangedState state) {
+  return ignored_changed_states[static_cast<size_t>(state)];
 }
 
 }  // namespace
@@ -696,7 +716,8 @@
 
 void AXEventGenerator::TrimEventsDueToAncestorIgnoredChanged(
     AXNode* node,
-    std::map<AXNode*, bool>& ancestor_ignored_changed_map) {
+    std::map<AXNode*, IgnoredChangedStatesBitset>&
+        ancestor_ignored_changed_map) {
   DCHECK(node);
 
   // Recursively compute and cache ancestor ignored changed results in
@@ -708,37 +729,86 @@
                                           ancestor_ignored_changed_map);
   }
 
-  // If an ancestor of |node| changed to ignored state, update the corresponding
-  // entry in the map for |node| based on the ancestor result (i.e. if an
-  // ancestor changed to ignored state, set the entry in the map to true for the
-  // current node). If |node|'s state changed to ignored as well, we want to
-  // remove its IGNORED_CHANGED event.
-  const auto& map_iter = ancestor_ignored_changed_map.find(node->parent());
-  const auto& events_iter = tree_events_.find(node);
-  if (map_iter != ancestor_ignored_changed_map.end() && map_iter->second) {
-    ancestor_ignored_changed_map.insert(std::make_pair(node, true));
-    if (node->IsIgnored() && events_iter != tree_events_.end()) {
-      RemoveEvent(&(events_iter->second), Event::IGNORED_CHANGED);
-      RemoveEventsDueToIgnoredChanged(&(events_iter->second));
+  // If an ancestor of |node| changed to ignored state (hide), append hide state
+  // to the corresponding entry in the map for |node|. Similarly, if an ancestor
+  // of |node| removed its ignored state (show), we append show state to the
+  // corresponding entry in map for |node| as well. If |node| flipped its
+  // ignored state as well, we want to remove various events related to
+  // IGNORED_CHANGED event.
+  const auto& parent_map_iter =
+      ancestor_ignored_changed_map.find(node->parent());
+  const auto& curr_events_iter = tree_events_.find(node);
+
+  // Initialize |ancestor_ignored_changed_map[node]| with an empty bitset,
+  // representing neither |node| nor its ancestor has IGNORED_CHANGED.
+  IgnoredChangedStatesBitset& ancestor_ignored_changed_states =
+      ancestor_ignored_changed_map[node];
+
+  // If |ancestor_ignored_changed_map| contains an entry for |node|'s
+  // ancestor's and the ancestor has either show/hide state, we want to populate
+  // |node|'s show/hide state in the map based on its cached ancestor result.
+  // An empty entry in |ancestor_ignored_changed_map| for |node| means that
+  // neither |node| nor its ancestor has IGNORED_CHANGED.
+  if (parent_map_iter != ancestor_ignored_changed_map.end()) {
+    // Propagate ancestor's show/hide states to |node|'s entry in the map.
+    if (HasIgnoredChangedState(parent_map_iter->second,
+                               IgnoredChangedState::kHide)) {
+      AddIgnoredChangedState(ancestor_ignored_changed_states,
+                             IgnoredChangedState::kHide);
     }
+    if (HasIgnoredChangedState(parent_map_iter->second,
+                               IgnoredChangedState::kShow)) {
+      AddIgnoredChangedState(ancestor_ignored_changed_states,
+                             IgnoredChangedState::kShow);
+    }
+
+    // If |node| has IGNORED changed with show/hide state that matches one of
+    // its ancestors' IGNORED changed show/hide states, we want to remove
+    // |node|'s IGNORED_CHANGED related events.
+    if (curr_events_iter != tree_events_.end() &&
+        HasEvent(curr_events_iter->second, Event::IGNORED_CHANGED)) {
+      if ((HasIgnoredChangedState(parent_map_iter->second,
+                                  IgnoredChangedState::kHide) &&
+           node->IsIgnored()) ||
+          (HasIgnoredChangedState(parent_map_iter->second,
+                                  IgnoredChangedState::kShow) &&
+           !node->IsIgnored())) {
+        RemoveEvent(&(curr_events_iter->second), Event::IGNORED_CHANGED);
+        RemoveEventsDueToIgnoredChanged(&(curr_events_iter->second));
+      }
+
+      if (node->IsIgnored()) {
+        AddIgnoredChangedState(ancestor_ignored_changed_states,
+                               IgnoredChangedState::kHide);
+      } else {
+        AddIgnoredChangedState(ancestor_ignored_changed_states,
+                               IgnoredChangedState::kShow);
+      }
+    }
+
     return;
   }
 
-  // If ignored changed results are not cached, calculate the corresponding
-  // entry for |node| in the map using the ignored states and events of |node|.
-  if (events_iter != tree_events_.end() &&
-      HasEvent(events_iter->second, Event::IGNORED_CHANGED) &&
-      node->IsIgnored()) {
-    ancestor_ignored_changed_map.insert(std::make_pair(node, true));
+  // If ignored changed results for ancestors are not cached, calculate the
+  // corresponding entry for |node| in the map using the ignored states and
+  // events of |node|.
+  if (curr_events_iter != tree_events_.end() &&
+      HasEvent(curr_events_iter->second, Event::IGNORED_CHANGED)) {
+    if (node->IsIgnored()) {
+      AddIgnoredChangedState(ancestor_ignored_changed_states,
+                             IgnoredChangedState::kHide);
+    } else {
+      AddIgnoredChangedState(ancestor_ignored_changed_states,
+                             IgnoredChangedState::kShow);
+    }
+
     return;
   }
-
-  ancestor_ignored_changed_map.insert(std::make_pair(node, false));
 }
 
 void AXEventGenerator::PostprocessEvents() {
-  std::map<AXNode*, bool> ancestor_ignored_changed_map;
-
+  std::map<AXNode*, IgnoredChangedStatesBitset> ancestor_ignored_changed_map;
+  std::set<AXNode*> removed_subtree_created_nodes;
   auto iter = tree_events_.begin();
   while (iter != tree_events_.end()) {
     AXNode* node = iter->first;
@@ -752,10 +822,10 @@
     }
 
     if (HasEvent(node_events, Event::IGNORED_CHANGED)) {
-      // If a node toggled its ignored state from show to hide, we only want to
-      // fire IGNORED_CHANGED event on the top most ancestor where this ignored
-      // state change takes place and suppress all the descendants's
-      // IGNORED_CHANGED events.
+      // If a node toggled its ignored state, we only want to fire
+      // IGNORED_CHANGED event on the top most ancestor where this ignored state
+      // change takes place and suppress all the descendants's IGNORED_CHANGED
+      // events.
       TrimEventsDueToAncestorIgnoredChanged(node, ancestor_ignored_changed_map);
       RemoveEventsDueToIgnoredChanged(&node_events);
     }
@@ -781,13 +851,18 @@
 
     // Don't fire subtree created on this node if any of its ancestors also has
     // subtree created.
-    while (parent && HasEvent(node_events, Event::SUBTREE_CREATED) &&
-           tree_events_.find(parent) != tree_events_.end()) {
-      if (HasEvent(tree_events_[parent], Event::SUBTREE_CREATED)) {
-        RemoveEvent(&node_events, Event::SUBTREE_CREATED);
-        break;
+    if (HasEvent(node_events, Event::SUBTREE_CREATED)) {
+      while (parent &&
+             (tree_events_.find(parent) != tree_events_.end() ||
+              base::Contains(removed_subtree_created_nodes, parent))) {
+        if (base::Contains(removed_subtree_created_nodes, parent) ||
+            HasEvent(tree_events_[parent], Event::SUBTREE_CREATED)) {
+          RemoveEvent(&node_events, Event::SUBTREE_CREATED);
+          removed_subtree_created_nodes.insert(node);
+          break;
+        }
+        parent = parent->GetUnignoredParent();
       }
-      parent = parent->GetUnignoredParent();
     }
 
     // If this was the only event, remove the node entirely from the
diff --git a/ui/accessibility/ax_event_generator.h b/ui/accessibility/ax_event_generator.h
index 4baef9f..5fa24397 100644
--- a/ui/accessibility/ax_event_generator.h
+++ b/ui/accessibility/ax_event_generator.h
@@ -101,6 +101,10 @@
     WIN_IACCESSIBLE_STATE_CHANGED,
   };
 
+  // For distinguishing between show and hide state when a node has
+  // IGNORED_CHANGED event.
+  enum class IgnoredChangedState : uint8_t { kShow, kHide, kCount = 2 };
+
   struct EventParams {
     EventParams(Event event,
                 ax::mojom::EventFrom event_from,
@@ -140,6 +144,16 @@
     std::set<EventParams>::const_iterator set_iter_;
   };
 
+  // For storing ignored changed states for a particular node. We use bitset as
+  // the underlying data structure to improve memory usage.
+  // We use the index of AXEventGenerator::IgnoredChangedState enum
+  // to access the bitset data.
+  // e.g. AXEventGenerator::IgnoredChangedState::kShow has index 0 in the
+  // IgnoredChangedState enum. If |IgnoredChangedStatesBitset[0]| is set, it
+  // means IgnoredChangedState::kShow is present. Similarly, kHide has index 1
+  // in the enum, and it corresponds to |IgnoredChangedStatesBitset[1]|.
+  using IgnoredChangedStatesBitset =
+      std::bitset<static_cast<size_t>(IgnoredChangedState::kCount)>;
   using const_iterator = Iterator;
   using iterator = Iterator;
   using value_type = TargetedEvent;
@@ -240,17 +254,23 @@
   void FireRelationSourceEvents(AXTree* tree, AXNode* target_node);
   bool ShouldFireLoadEvents(AXNode* node);
   // Remove excessive events for a tree update containing node.
-  // We remove certain events on a node when it changes to IGNORED state and one
-  // of the node's ancestor has also changed to IGNORED in the same tree update.
+  // We remove certain events on a node when it flips its IGNORED state to
+  // either show/hide and one of the node's ancestor has also flipped its
+  // IGNORED state in the same way (show/hide) in the tree update.
   // |ancestor_has_ignored_map| contains if a node's ancestor has changed to
   // IGNORED state.
-  // Map's key is: an ax node.
-  // Map's value is:
-  // - True if an ancestor of node changed to IGNORED state.
-  // - False if no ancestor of node changed to IGNORED state.
+  // Map's key is an AXNode.
+  // Map's value is a std::bitset containing IgnoredChangedStates(kShow/kHide).
+  // - Map's value IgnoredChangedStatesBitset contains kShow if an ancestor
+  //   of node removed its IGNORED state.
+  // - Map's value IgnoredChangedStatesBitset contains kHide if an ancestor
+  //   of node changed to IGNORED state.
+  // - When IgnoredChangedStatesBitset is not set, it means neither the
+  //   node nor its ancestor has IGNORED_CHANGED.
   void TrimEventsDueToAncestorIgnoredChanged(
       AXNode* node,
-      std::map<AXNode*, bool>& ancestor_has_ignored_map);
+      std::map<AXNode*, IgnoredChangedStatesBitset>&
+          ancestor_ignored_changed_map);
   void PostprocessEvents();
   static void GetRestrictionStates(ax::mojom::Restriction restriction,
                                    bool* is_enabled,
diff --git a/ui/accessibility/ax_event_generator_unittest.cc b/ui/accessibility/ax_event_generator_unittest.cc
index e54ba4f..e7d7e24a 100644
--- a/ui/accessibility/ax_event_generator_unittest.cc
+++ b/ui/accessibility/ax_event_generator_unittest.cc
@@ -1102,8 +1102,7 @@
               UnorderedElementsAre(
                   HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
                   HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2),
-                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
-                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3)));
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2)));
 }
 
 TEST(AXEventGeneratorTest, TwoNodesSwapIgnored) {
@@ -1169,6 +1168,7 @@
   //   1 (IGN)
   //  / \
   // 2   3 (IGN)
+
   // AFTER
   //   1 (IGN)
   //  /      \
@@ -1211,6 +1211,7 @@
   //   2
   //  / \
   // 3   4 (IGN)
+
   // AFTER
   //   1
   //   |
@@ -1259,6 +1260,7 @@
   //   2 ___
   //  /      \
   // 3 (IGN)  4
+
   // AFTER
   //   1 (IGN)
   //   |
@@ -1314,6 +1316,7 @@
   //    ____ 5  _____
   //  /       |       \
   // 6 (IGN)  7 (IGN)  8
+
   // AFTER
   //         1 (IGN)
   //         |
@@ -1396,6 +1399,7 @@
   //    ____ 5  _____
   //  /       |       \
   // 6 (IGN)  7        8
+
   // AFTER
   //         1 (IGN)
   //         |
@@ -1476,6 +1480,7 @@
   //    ____ 5  _____
   //  /       |       \
   // 6 (IGN)  7 (IGN)  8
+
   // AFTER
   //         1
   //         |
@@ -1489,7 +1494,7 @@
   //  /       |       \
   // 6        7        8 (IGN)
 
-  // IGNORED_CHANGED expected on #1, #6, #7, #8
+  // IGNORED_CHANGED expected on #1, #8
 
   AXTreeUpdate initial_state;
   initial_state.root_id = 1;
@@ -1542,8 +1547,6 @@
                   HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 6),
                   HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 7),
                   HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
-                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 6),
-                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 7),
                   HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 8)));
 }
 
@@ -1558,6 +1561,7 @@
   //    __ 4 ___
   //  /          \
   // 5 (IGN)      6 (IGN)
+
   // AFTER
   //       1
   //       |
@@ -1569,7 +1573,7 @@
   //  /           \
   // 5 (IGN)       6 (IGN)
 
-  // IGNORED_CHANGED expected on #1, #2, #3
+  // IGNORED_CHANGED expected on #1, #3
 
   AXTreeUpdate initial_state;
   initial_state.root_id = 1;
@@ -1613,10 +1617,91 @@
               UnorderedElementsAre(
                   HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 1),
                   HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 1),
-                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
                   HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 3)));
 }
 
+TEST(AXEventGeneratorTest, IgnoredChangedFiredOnAncestorOnly8) {
+  // BEFORE
+  //         ____ 1 ____
+  //       |            |
+  //       2 (IGN)      7
+  //       |
+  //       3 (IGN)
+  //       |
+  //       4 (IGN)
+  //       |
+  //       5 (IGN)
+  //       |
+  //       6 (IGN)
+
+  // AFTER
+  //         ____ 1 ____
+  //       |            |
+  //       2            7 (IGN)
+  //       |
+  //       3
+  //       |
+  //       4
+  //       |
+  //       5
+  //       |
+  //       6
+
+  // IGNORED_CHANGED expected on #2, #7
+
+  AXTreeUpdate initial_state;
+  initial_state.root_id = 1;
+  initial_state.nodes.resize(7);
+  initial_state.nodes[0].id = 1;
+  initial_state.nodes[0].role = ax::mojom::Role::kRootWebArea;
+  initial_state.nodes[0].child_ids = {2, 7};
+
+  initial_state.nodes[1].id = 2;
+  initial_state.nodes[1].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[1].child_ids = {3};
+  initial_state.nodes[1].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[2].id = 3;
+  initial_state.nodes[2].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[2].child_ids = {4};
+  initial_state.nodes[2].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[3].id = 4;
+  initial_state.nodes[3].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[3].child_ids = {5};
+  initial_state.nodes[3].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[4].id = 5;
+  initial_state.nodes[4].role = ax::mojom::Role::kGroup;
+  initial_state.nodes[4].child_ids = {6};
+  initial_state.nodes[4].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[5].id = 5;
+  initial_state.nodes[5].role = ax::mojom::Role::kStaticText;
+  initial_state.nodes[5].AddState(ax::mojom::State::kIgnored);
+
+  initial_state.nodes[6].id = 7;
+  initial_state.nodes[6].role = ax::mojom::Role::kStaticText;
+
+  AXTree tree(initial_state);
+
+  AXEventGenerator event_generator(&tree);
+  AXTreeUpdate update = initial_state;
+  update.nodes[1].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[2].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[3].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[4].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[5].RemoveState(ax::mojom::State::kIgnored);
+  update.nodes[6].AddState(ax::mojom::State::kIgnored);
+  ASSERT_TRUE(tree.Unserialize(update));
+  EXPECT_THAT(event_generator,
+              UnorderedElementsAre(
+                  HasEventAtNode(AXEventGenerator::Event::CHILDREN_CHANGED, 1),
+                  HasEventAtNode(AXEventGenerator::Event::SUBTREE_CREATED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 2),
+                  HasEventAtNode(AXEventGenerator::Event::IGNORED_CHANGED, 7)));
+}
+
 TEST(AXEventGeneratorTest, ActiveDescendantChangeOnDescendant) {
   AXTreeUpdate initial_state;
   initial_state.root_id = 1;
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
index e136a1e..991781af 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
@@ -371,14 +371,12 @@
    * Returns an 'error' MetadataItem.
    * @param {string} url File entry.
    * @param {string} step Step that failed.
-   * @param {string} errorDescription Error description.
+   * @param {string} cause Error cause.
    * @return {!MetadataItem} Error metadata
    * @private
    */
-  createError_(url, step, errorDescription) {
-    // For error case, fill all fields with error object.
-    const error =
-        new ContentMetadataProvider.Error(url, step, errorDescription);
+  createError_(url, step, cause) {
+    const error = new ContentMetadataProvider.Error(url, step, cause);
     const item = new MetadataItem();
     item.contentImageTransformError = error;
     item.contentThumbnailTransformError = error;
@@ -394,10 +392,10 @@
   /**
    * @param {string} url File Entry.
    * @param {string} step Step that failed.
-   * @param {string} errorDescription Error description.
+   * @param {string} cause Error cause.
    */
-  constructor(url, step, errorDescription) {
-    super(errorDescription);
+  constructor(url, step, cause) {
+    super(cause);
 
     /** @public @const {string} */
     this.url = url;
@@ -406,7 +404,7 @@
     this.step = step;
 
     /** @public @const {string} */
-    this.errorDescription = errorDescription;
+    this.errorDescription = cause;
   }
 };
 
diff --git a/ui/gl/direct_composition_child_surface_win.cc b/ui/gl/direct_composition_child_surface_win.cc
index 387fe3d6..e1db24c 100644
--- a/ui/gl/direct_composition_child_surface_win.cc
+++ b/ui/gl/direct_composition_child_surface_win.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/process/process.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #include "base/win/windows_version.h"
@@ -25,6 +26,7 @@
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/gl_utils.h"
 #include "ui/gl/scoped_make_current.h"
+#include "ui/gl/vsync_thread_win.h"
 
 #ifndef EGL_ANGLE_flexible_surface_compatibility
 #define EGL_ANGLE_flexible_surface_compatibility 1
@@ -47,11 +49,33 @@
 IDCompositionSurface* g_current_surface = nullptr;
 
 bool g_direct_composition_swap_chain_failed = false;
+
+bool SupportsLowLatencyPresentation() {
+  return base::FeatureList::IsEnabled(
+      features::kDirectCompositionLowLatencyPresentation);
+}
 }  // namespace
 
+DirectCompositionChildSurfaceWin::PendingFrame::PendingFrame(
+    Microsoft::WRL::ComPtr<ID3D11Query> query,
+    PresentationCallback callback)
+    : query(std::move(query)), callback(std::move(callback)) {}
+DirectCompositionChildSurfaceWin::PendingFrame::PendingFrame(
+    PendingFrame&& other) = default;
+DirectCompositionChildSurfaceWin::PendingFrame::~PendingFrame() = default;
+DirectCompositionChildSurfaceWin::PendingFrame&
+DirectCompositionChildSurfaceWin::PendingFrame::operator=(
+    PendingFrame&& other) = default;
+
 DirectCompositionChildSurfaceWin::DirectCompositionChildSurfaceWin(
-    bool use_angle_texture_offset)
-    : use_angle_texture_offset_(use_angle_texture_offset) {}
+    VSyncCallback vsync_callback,
+    bool use_angle_texture_offset,
+    size_t max_pending_frames)
+    : vsync_callback_(std::move(vsync_callback)),
+      use_angle_texture_offset_(use_angle_texture_offset),
+      max_pending_frames_(max_pending_frames),
+      vsync_thread_(VSyncThreadWin::GetInstance()),
+      task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
 DirectCompositionChildSurfaceWin::~DirectCompositionChildSurfaceWin() {
   Destroy();
@@ -185,6 +209,13 @@
 }
 
 void DirectCompositionChildSurfaceWin::Destroy() {
+  for (auto& frame : pending_frames_)
+    std::move(frame.callback).Run(gfx::PresentationFeedback::Failure());
+  pending_frames_.clear();
+
+  if (vsync_thread_started_)
+    vsync_thread_->RemoveObserver(this);
+
   if (default_surface_) {
     if (!eglDestroySurface(GetDisplay(), default_surface_)) {
       DLOG(ERROR) << "eglDestroySurface failed with error "
@@ -225,13 +256,12 @@
     PresentationCallback callback) {
   TRACE_EVENT1("gpu", "DirectCompositionChildSurfaceWin::SwapBuffers", "size",
                size_.ToString());
-  // PresentationCallback is handled by DirectCompositionSurfaceWin. The child
-  // surface doesn't need to provide presentation feedback.
-  DCHECK(!callback);
 
-  return ReleaseDrawTexture(false /* will_discard */)
-             ? gfx::SwapResult::SWAP_ACK
-             : gfx::SwapResult::SWAP_FAILED;
+  gfx::SwapResult swap_result = ReleaseDrawTexture(false /* will_discard */)
+                                    ? gfx::SwapResult::SWAP_ACK
+                                    : gfx::SwapResult::SWAP_FAILED;
+  EnqueuePendingFrame(std::move(callback));
+  return swap_result;
 }
 
 gfx::SurfaceOrigin DirectCompositionChildSurfaceWin::GetOrigin() const {
@@ -519,6 +549,128 @@
   }
 }
 
+gfx::VSyncProvider* DirectCompositionChildSurfaceWin::GetVSyncProvider() {
+  return vsync_thread_->vsync_provider();
+}
+
+bool DirectCompositionChildSurfaceWin::SupportsGpuVSync() const {
+  return true;
+}
+
+void DirectCompositionChildSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
+  {
+    base::AutoLock auto_lock(vsync_callback_enabled_lock_);
+    vsync_callback_enabled_ = enabled;
+  }
+  StartOrStopVSyncThread();
+}
+
+void DirectCompositionChildSurfaceWin::OnVSync(base::TimeTicks vsync_time,
+                                               base::TimeDelta interval) {
+  // Main thread will run vsync callback in low latency presentation mode.
+  if (VSyncCallbackEnabled() && !SupportsLowLatencyPresentation()) {
+    DCHECK(vsync_callback_);
+    vsync_callback_.Run(vsync_time, interval);
+  }
+
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&DirectCompositionChildSurfaceWin::HandleVSyncOnMainThread,
+                     weak_factory_.GetWeakPtr(), vsync_time, interval));
+}
+
+void DirectCompositionChildSurfaceWin::HandleVSyncOnMainThread(
+    base::TimeTicks vsync_time,
+    base::TimeDelta interval) {
+  last_vsync_time_ = vsync_time;
+  last_vsync_interval_ = interval;
+
+  CheckPendingFrames();
+
+  UMA_HISTOGRAM_COUNTS_100("GPU.DirectComposition.NumPendingFrames",
+                           pending_frames_.size());
+
+  if (SupportsLowLatencyPresentation() && VSyncCallbackEnabled() &&
+      pending_frames_.size() < max_pending_frames_) {
+    DCHECK(vsync_callback_);
+    vsync_callback_.Run(vsync_time, interval);
+  }
+}
+
+void DirectCompositionChildSurfaceWin::StartOrStopVSyncThread() {
+  bool start_vsync_thread = VSyncCallbackEnabled() || !pending_frames_.empty();
+  if (vsync_thread_started_ == start_vsync_thread)
+    return;
+  vsync_thread_started_ = start_vsync_thread;
+  if (start_vsync_thread) {
+    vsync_thread_->AddObserver(this);
+  } else {
+    vsync_thread_->RemoveObserver(this);
+  }
+}
+
+bool DirectCompositionChildSurfaceWin::VSyncCallbackEnabled() const {
+  base::AutoLock auto_lock(vsync_callback_enabled_lock_);
+  return vsync_callback_enabled_;
+}
+
+void DirectCompositionChildSurfaceWin::CheckPendingFrames() {
+  TRACE_EVENT1("gpu", "DirectCompositionChildSurfaceWin::CheckPendingFrames",
+               "num_pending_frames", pending_frames_.size());
+
+  if (pending_frames_.empty())
+    return;
+
+  Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
+  d3d11_device_->GetImmediateContext(&context);
+  while (!pending_frames_.empty()) {
+    auto& frame = pending_frames_.front();
+    // Query isn't created if there was no damage for previous frame.
+    if (frame.query) {
+      HRESULT hr = context->GetData(frame.query.Get(), nullptr, 0,
+                                    D3D11_ASYNC_GETDATA_DONOTFLUSH);
+      // When the GPU completes execution past the event query, GetData() will
+      // return S_OK, and S_FALSE otherwise.  Do not use SUCCEEDED() because
+      // S_FALSE is also a success code.
+      if (hr != S_OK)
+        break;
+    }
+    std::move(frame.callback)
+        .Run(
+            gfx::PresentationFeedback(last_vsync_time_, last_vsync_interval_,
+                                      gfx::PresentationFeedback::kVSync |
+                                          gfx::PresentationFeedback::kHWClock));
+    pending_frames_.pop_front();
+  }
+
+  StartOrStopVSyncThread();
+}
+
+void DirectCompositionChildSurfaceWin::EnqueuePendingFrame(
+    PresentationCallback callback) {
+  Microsoft::WRL::ComPtr<ID3D11Query> query;
+
+  // Do not create query for empty damage so that 3D engine is not used when
+  // only presenting video in overlay. Callback will be dequeued on next vsync.
+  if (!swap_rect_.IsEmpty()) {
+    D3D11_QUERY_DESC desc = {};
+    desc.Query = D3D11_QUERY_EVENT;
+    HRESULT hr = d3d11_device_->CreateQuery(&desc, &query);
+    if (SUCCEEDED(hr)) {
+      Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
+      d3d11_device_->GetImmediateContext(&context);
+      context->End(query.Get());
+      context->Flush();
+    } else {
+      DLOG(ERROR) << "CreateQuery failed with error 0x" << std::hex << hr;
+    }
+  }
+
+  pending_frames_.emplace_back(std::move(query), std::move(callback));
+
+  StartOrStopVSyncThread();
+}
+
 // static
 bool DirectCompositionChildSurfaceWin::IsDirectCompositionSwapChainFailed() {
   return g_direct_composition_swap_chain_failed;
diff --git a/ui/gl/direct_composition_child_surface_win.h b/ui/gl/direct_composition_child_surface_win.h
index 4ecf6f0..4690bb6 100644
--- a/ui/gl/direct_composition_child_surface_win.h
+++ b/ui/gl/direct_composition_child_surface_win.h
@@ -10,14 +10,30 @@
 #include <dcomp.h>
 #include <wrl/client.h>
 
+#include "base/callback.h"
+#include "base/containers/circular_deque.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
 #include "ui/gl/gl_export.h"
 #include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/vsync_observer.h"
+
+namespace base {
+class SequencedTaskRunner;
+}  // namespace base
 
 namespace gl {
+class VSyncThreadWin;
 
-class GL_EXPORT DirectCompositionChildSurfaceWin : public GLSurfaceEGL {
+class GL_EXPORT DirectCompositionChildSurfaceWin : public GLSurfaceEGL,
+                                                   public VSyncObserver {
  public:
-  explicit DirectCompositionChildSurfaceWin(bool use_angle_texture_offset);
+  using VSyncCallback =
+      base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
+  DirectCompositionChildSurfaceWin(VSyncCallback vsync_callback,
+                                   bool use_angle_texture_offset,
+                                   size_t max_pending_frames);
 
   // GLSurfaceEGL implementation.
   bool Initialize(GLSurfaceFormat format) override;
@@ -39,6 +55,12 @@
               bool has_alpha) override;
   bool SetEnableDCLayers(bool enable) override;
   void SetFrameRate(float frame_rate) override;
+  gfx::VSyncProvider* GetVSyncProvider() override;
+  bool SupportsGpuVSync() const override;
+  void SetGpuVSyncEnabled(bool enabled) override;
+
+  // VSyncObserver implementation.
+  void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
 
   static bool IsDirectCompositionSwapChainFailed();
 
@@ -59,17 +81,39 @@
   ~DirectCompositionChildSurfaceWin() override;
 
  private:
+  struct PendingFrame {
+    PendingFrame(Microsoft::WRL::ComPtr<ID3D11Query> query,
+                 PresentationCallback callback);
+    PendingFrame(PendingFrame&& other);
+    ~PendingFrame();
+    PendingFrame& operator=(PendingFrame&& other);
+
+    // Event query issued after frame is presented.
+    Microsoft::WRL::ComPtr<ID3D11Query> query;
+
+    // Presentation callback enqueued in SwapBuffers().
+    PresentationCallback callback;
+  };
+
+  void EnqueuePendingFrame(PresentationCallback callback);
+  void CheckPendingFrames();
+
+  void StartOrStopVSyncThread();
+
+  bool VSyncCallbackEnabled() const;
+
+  void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
+                               base::TimeDelta interval);
+
   // Release the texture that's currently being drawn to. If will_discard is
   // true then the surface should be discarded without swapping any contents
   // to it. Returns false if this fails.
   bool ReleaseDrawTexture(bool will_discard);
 
-  // This is called when a new swap chain is created, or when a new frame
-  // rate is received.
+  // This is called when a new swap chain is created, or when a new frame rate
+  // is received.
   void SetSwapChainPresentDuration();
 
-  const bool use_angle_texture_offset_;
-
   gfx::Size size_ = gfx::Size(1, 1);
   bool enable_dc_layers_ = false;
   bool has_alpha_ = true;
@@ -101,6 +145,25 @@
   // Number of frames per second.
   float frame_rate_ = 0.f;
 
+  const VSyncCallback vsync_callback_;
+  const bool use_angle_texture_offset_;
+  const size_t max_pending_frames_;
+
+  VSyncThreadWin* const vsync_thread_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  bool vsync_thread_started_ = false;
+  bool vsync_callback_enabled_ GUARDED_BY(vsync_callback_enabled_lock_) = false;
+  mutable base::Lock vsync_callback_enabled_lock_;
+
+  // Queue of pending presentation callbacks.
+  base::circular_deque<PendingFrame> pending_frames_;
+
+  base::TimeTicks last_vsync_time_;
+  base::TimeDelta last_vsync_interval_;
+
+  base::WeakPtrFactory<DirectCompositionChildSurfaceWin> weak_factory_{this};
+
   DISALLOW_COPY_AND_ASSIGN(DirectCompositionChildSurfaceWin);
 };
 
diff --git a/ui/gl/direct_composition_surface_win.cc b/ui/gl/direct_composition_surface_win.cc
index 87c4729..6406d7d8 100644
--- a/ui/gl/direct_composition_surface_win.cc
+++ b/ui/gl/direct_composition_surface_win.cc
@@ -14,7 +14,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/synchronization/lock.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
 #include "base/win/windows_version.h"
@@ -22,10 +21,8 @@
 #include "ui/gl/direct_composition_child_surface_win.h"
 #include "ui/gl/gl_angle_util_win.h"
 #include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_presentation_helper.h"
 #include "ui/gl/gl_switches.h"
 #include "ui/gl/gpu_switching_manager.h"
-#include "ui/gl/vsync_thread_win.h"
 
 #ifndef EGL_ANGLE_flexible_surface_compatibility
 #define EGL_ANGLE_flexible_surface_compatibility 1
@@ -319,57 +316,26 @@
   g_overlay_monitor_size = overlay_monitor_size;
 }
 
-bool SupportsPresentationFeedback() {
-  return base::FeatureList::IsEnabled(
-             features::kDirectCompositionPresentationFeedback) &&
-         base::FeatureList::IsEnabled(features::kDirectCompositionGpuVSync);
-}
-
-bool SupportsLowLatencyPresentation() {
-  return base::FeatureList::IsEnabled(
-             features::kDirectCompositionLowLatencyPresentation) &&
-         SupportsPresentationFeedback();
-}
-
 void RunOverlayHdrGpuInfoUpdateCallback() {
   if (g_overlay_hdr_gpu_info_callback)
     g_overlay_hdr_gpu_info_callback.Run();
 }
 }  // namespace
 
-DirectCompositionSurfaceWin::PendingFrame::PendingFrame(
-    Microsoft::WRL::ComPtr<ID3D11Query> query,
-    PresentationCallback callback)
-    : query(std::move(query)), callback(std::move(callback)) {}
-DirectCompositionSurfaceWin::PendingFrame::PendingFrame(PendingFrame&& other) =
-    default;
-DirectCompositionSurfaceWin::PendingFrame::~PendingFrame() = default;
-DirectCompositionSurfaceWin::PendingFrame&
-DirectCompositionSurfaceWin::PendingFrame::operator=(PendingFrame&& other) =
-    default;
-
 DirectCompositionSurfaceWin::DirectCompositionSurfaceWin(
-    std::unique_ptr<gfx::VSyncProvider> vsync_provider,
-    VSyncCallback vsync_callback,
     HWND parent_window,
+    VSyncCallback vsync_callback,
     const Settings& settings)
     : GLSurfaceEGL(),
       child_window_(parent_window),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()),
       root_surface_(new DirectCompositionChildSurfaceWin(
-          settings.use_angle_texture_offset)),
+          std::move(vsync_callback),
+          settings.use_angle_texture_offset,
+          settings.max_pending_frames)),
       layer_tree_(std::make_unique<DCLayerTree>(
           settings.disable_nv12_dynamic_textures,
           settings.disable_larger_than_screen_overlays,
-          settings.disable_vp_scaling)),
-      presentation_helper_(
-          std::make_unique<GLSurfacePresentationHelper>(vsync_provider.get())),
-      vsync_provider_(std::move(vsync_provider)),
-      vsync_callback_(std::move(vsync_callback)),
-      max_pending_frames_(settings.max_pending_frames) {
-  // Call GetWeakPtr() on main thread before calling on vsync thread so that the
-  // internal weak reference is initialized in a thread-safe way.
-  weak_ptr_ = weak_factory_.GetWeakPtr();
+          settings.disable_vp_scaling)) {
   ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
 }
 
@@ -696,25 +662,11 @@
   if (!root_surface_->Initialize(GLSurfaceFormat()))
     return false;
 
-  if ((SupportsGpuVSync() && vsync_callback_) || SupportsPresentationFeedback())
-    vsync_thread_ = VSyncThreadWin::GetInstance();
-
   return true;
 }
 
 void DirectCompositionSurfaceWin::Destroy() {
-  for (auto& frame : pending_frames_)
-    std::move(frame.callback).Run(gfx::PresentationFeedback::Failure());
-  pending_frames_.clear();
-
-  if (vsync_thread_) {
-    vsync_thread_->RemoveObserver(this);
-    vsync_thread_ = nullptr;
-  }
-  // Destroy presentation helper first because its dtor calls GetHandle.
-  presentation_helper_ = nullptr;
   root_surface_->Destroy();
-
   // Freeing DComp resources such as visuals and surfaces causes the
   // device to become 'dirty'. We must commit the changes to the device
   // in order for the objects to actually be destroyed.
@@ -755,29 +707,14 @@
     PresentationCallback callback) {
   TRACE_EVENT0("gpu", "DirectCompositionSurfaceWin::SwapBuffers");
 
-  base::Optional<GLSurfacePresentationHelper::ScopedSwapBuffers>
-      scoped_swap_buffers;
-  if (!SupportsPresentationFeedback()) {
-    scoped_swap_buffers.emplace(presentation_helper_.get(),
-                                std::move(callback));
-  }
+  if (root_surface_->SwapBuffers(std::move(callback)) !=
+      gfx::SwapResult::SWAP_ACK)
+    return gfx::SwapResult::SWAP_FAILED;
 
-  gfx::SwapResult swap_result;
-  if (root_surface_->SwapBuffers(PresentationCallback()) ==
-          gfx::SwapResult::SWAP_ACK &&
-      layer_tree_->CommitAndClearPendingOverlays(root_surface_.get())) {
-    swap_result = gfx::SwapResult::SWAP_ACK;
-  } else {
-    swap_result = gfx::SwapResult::SWAP_FAILED;
-  }
+  if (!layer_tree_->CommitAndClearPendingOverlays(root_surface_.get()))
+    return gfx::SwapResult::SWAP_FAILED;
 
-  if (scoped_swap_buffers) {
-    scoped_swap_buffers->set_result(swap_result);
-  } else {
-    EnqueuePendingFrame(std::move(callback));
-  }
-
-  return swap_result;
+  return gfx::SwapResult::SWAP_ACK;
 }
 
 gfx::SwapResult DirectCompositionSurfaceWin::PostSubBuffer(
@@ -792,7 +729,7 @@
 }
 
 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() {
-  return vsync_provider_.get();
+  return root_surface_->GetVSyncProvider();
 }
 
 void DirectCompositionSurfaceWin::SetVSyncEnabled(bool enabled) {
@@ -822,8 +759,6 @@
 }
 
 bool DirectCompositionSurfaceWin::OnMakeCurrent(GLContext* context) {
-  if (presentation_helper_)
-    presentation_helper_->OnMakeCurrent(context, this);
   return root_surface_->OnMakeCurrent(context);
 }
 
@@ -852,118 +787,11 @@
 }
 
 bool DirectCompositionSurfaceWin::SupportsGpuVSync() const {
-  return base::FeatureList::IsEnabled(features::kDirectCompositionGpuVSync);
+  return true;
 }
 
 void DirectCompositionSurfaceWin::SetGpuVSyncEnabled(bool enabled) {
-  DCHECK(vsync_thread_);
-  {
-    base::AutoLock lock(vsync_callback_lock_);
-    vsync_callback_enabled_ = enabled;
-  }
-  StartOrStopVSyncThread();
-}
-
-void DirectCompositionSurfaceWin::CheckPendingFrames() {
-  DCHECK(SupportsPresentationFeedback());
-
-  TRACE_EVENT1("gpu", "DirectCompositionSurfaceWin::CheckPendingFrames",
-               "num_pending_frames", pending_frames_.size());
-
-  if (pending_frames_.empty())
-    return;
-
-  Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-  d3d11_device_->GetImmediateContext(&context);
-  while (!pending_frames_.empty()) {
-    auto& frame = pending_frames_.front();
-    if (frame.query) {
-      HRESULT hr = context->GetData(frame.query.Get(), nullptr, 0,
-                                    D3D11_ASYNC_GETDATA_DONOTFLUSH);
-      // When the GPU completes execution past the event query, GetData() will
-      // return S_OK, and S_FALSE otherwise.  Do not use SUCCEEDED() because
-      // S_FALSE is also a success code.
-      if (hr != S_OK)
-        break;
-    }
-    std::move(frame.callback)
-        .Run(
-            gfx::PresentationFeedback(last_vsync_time_, last_vsync_interval_,
-                                      gfx::PresentationFeedback::kVSync |
-                                          gfx::PresentationFeedback::kHWClock));
-    pending_frames_.pop_front();
-  }
-
-  StartOrStopVSyncThread();
-}
-
-void DirectCompositionSurfaceWin::EnqueuePendingFrame(
-    PresentationCallback callback) {
-  DCHECK(SupportsPresentationFeedback());
-
-  Microsoft::WRL::ComPtr<ID3D11Query> query;
-  D3D11_QUERY_DESC desc = {};
-  desc.Query = D3D11_QUERY_EVENT;
-
-  HRESULT hr = d3d11_device_->CreateQuery(&desc, &query);
-  if (SUCCEEDED(hr)) {
-    Microsoft::WRL::ComPtr<ID3D11DeviceContext> context;
-    d3d11_device_->GetImmediateContext(&context);
-    context->End(query.Get());
-    context->Flush();
-  } else {
-    DLOG(ERROR) << "CreateQuery failed with error 0x" << std::hex << hr;
-  }
-
-  pending_frames_.emplace_back(std::move(query), std::move(callback));
-
-  StartOrStopVSyncThread();
-}
-
-bool DirectCompositionSurfaceWin::VSyncCallbackEnabled() const {
-  base::AutoLock lock(vsync_callback_lock_);
-  return vsync_callback_enabled_;
-}
-
-void DirectCompositionSurfaceWin::StartOrStopVSyncThread() {
-  if (VSyncCallbackEnabled() || !pending_frames_.empty()) {
-    vsync_thread_->AddObserver(this);
-  } else {
-    vsync_thread_->RemoveObserver(this);
-  }
-}
-
-void DirectCompositionSurfaceWin::OnVSync(base::TimeTicks vsync_time,
-                                          base::TimeDelta interval) {
-  if (!SupportsLowLatencyPresentation() && VSyncCallbackEnabled()) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
-
-  if (SupportsPresentationFeedback()) {
-    task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(&DirectCompositionSurfaceWin::HandleVSyncOnMainThread,
-                       weak_ptr_, vsync_time, interval));
-  }
-}
-
-void DirectCompositionSurfaceWin::HandleVSyncOnMainThread(
-    base::TimeTicks vsync_time,
-    base::TimeDelta interval) {
-  last_vsync_time_ = vsync_time;
-  last_vsync_interval_ = interval;
-
-  CheckPendingFrames();
-
-  UMA_HISTOGRAM_COUNTS_100("GPU.DirectComposition.NumPendingFrames",
-                           pending_frames_.size());
-
-  if (SupportsLowLatencyPresentation() && VSyncCallbackEnabled() &&
-      pending_frames_.size() < max_pending_frames_) {
-    DCHECK(vsync_callback_);
-    vsync_callback_.Run(vsync_time, interval);
-  }
+  root_surface_->SetGpuVSyncEnabled(enabled);
 }
 
 void DirectCompositionSurfaceWin::OnGpuSwitched(
diff --git a/ui/gl/direct_composition_surface_win.h b/ui/gl/direct_composition_surface_win.h
index 7e50e17..12c9d1d 100644
--- a/ui/gl/direct_composition_surface_win.h
+++ b/ui/gl/direct_composition_surface_win.h
@@ -21,16 +21,12 @@
 namespace gl {
 class DCLayerTree;
 class DirectCompositionChildSurfaceWin;
-class GLSurfacePresentationHelper;
-class VSyncThreadWin;
 
 class GL_EXPORT DirectCompositionSurfaceWin : public GLSurfaceEGL,
-                                              public VSyncObserver,
                                               public ui::GpuSwitchingObserver {
  public:
   using VSyncCallback =
       base::RepeatingCallback<void(base::TimeTicks, base::TimeDelta)>;
-
   using OverlayHDRInfoUpdateCallback = base::RepeatingClosure;
 
   struct Settings {
@@ -42,9 +38,8 @@
   };
 
   DirectCompositionSurfaceWin(
-      std::unique_ptr<gfx::VSyncProvider> vsync_provider,
-      VSyncCallback vsync_callback,
       HWND parent_window,
+      VSyncCallback vsync_callback,
       const DirectCompositionSurfaceWin::Settings& settings);
 
   // Returns true if direct composition is supported.  We prefer to use direct
@@ -140,9 +135,6 @@
   bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
   void SetFrameRate(float frame_rate) override;
 
-  // VSyncObserver implementation.
-  void OnVSync(base::TimeTicks vsync_time, base::TimeDelta interval) override;
-
   // Implements GpuSwitchingObserver.
   void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
   void OnDisplayAdded() override;
@@ -165,57 +157,15 @@
   ~DirectCompositionSurfaceWin() override;
 
  private:
-  struct PendingFrame {
-    PendingFrame(Microsoft::WRL::ComPtr<ID3D11Query> query,
-                 PresentationCallback callback);
-    PendingFrame(PendingFrame&& other);
-    ~PendingFrame();
-    PendingFrame& operator=(PendingFrame&& other);
-
-    // Event query issued after frame is presented.
-    Microsoft::WRL::ComPtr<ID3D11Query> query;
-
-    // Presentation callback enqueued in SwapBuffers().
-    PresentationCallback callback;
-  };
-
-  void EnqueuePendingFrame(PresentationCallback callback);
-  void CheckPendingFrames();
-
-  bool VSyncCallbackEnabled() const;
-
-  void StartOrStopVSyncThread();
-  void HandleVSyncOnMainThread(base::TimeTicks vsync_time,
-                               base::TimeDelta interval);
-
   HWND window_ = nullptr;
   ChildWindowWin child_window_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   scoped_refptr<DirectCompositionChildSurfaceWin> root_surface_;
   std::unique_ptr<DCLayerTree> layer_tree_;
-  std::unique_ptr<GLSurfacePresentationHelper> presentation_helper_;
-
-  std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
-
-  const VSyncCallback vsync_callback_;
-  mutable base::Lock vsync_callback_lock_;
-  bool GUARDED_BY(vsync_callback_lock_) vsync_callback_enabled_ = false;
-  VSyncThreadWin* vsync_thread_ = nullptr;
-
-  base::TimeTicks last_vsync_time_;
-  base::TimeDelta last_vsync_interval_;
-
-  // Queue of pending presentation callbacks.
-  base::circular_deque<PendingFrame> pending_frames_;
-  const size_t max_pending_frames_;
 
   Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device_;
   Microsoft::WRL::ComPtr<IDCompositionDevice2> dcomp_device_;
 
-  base::WeakPtr<DirectCompositionSurfaceWin> weak_ptr_;
-  base::WeakPtrFactory<DirectCompositionSurfaceWin> weak_factory_{this};
-
   DISALLOW_COPY_AND_ASSIGN(DirectCompositionSurfaceWin);
 };
 
diff --git a/ui/gl/direct_composition_surface_win_unittest.cc b/ui/gl/direct_composition_surface_win_unittest.cc
index c123d08..01e8103b 100644
--- a/ui/gl/direct_composition_surface_win_unittest.cc
+++ b/ui/gl/direct_composition_surface_win_unittest.cc
@@ -141,8 +141,7 @@
     DirectCompositionSurfaceWin::Settings settings;
     scoped_refptr<DirectCompositionSurfaceWin> surface =
         base::MakeRefCounted<DirectCompositionSurfaceWin>(
-            /*vsync_provider=*/nullptr,
-            DirectCompositionSurfaceWin::VSyncCallback(), parent_window_,
+            parent_window_, DirectCompositionSurfaceWin::VSyncCallback(),
             settings);
     EXPECT_TRUE(surface->Initialize(GLSurfaceFormat()));
 
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index d44a516..c850ff32 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -187,10 +187,6 @@
 const base::Feature kDirectCompositionForceFullDamage{
     "DirectCompositionForceFullDamage", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Use IDXGIOutput::WaitForVBlank() to drive begin frames.
-const base::Feature kDirectCompositionGpuVSync{
-    "DirectCompositionGpuVSync", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Use presentation feedback event queries (must be enabled) to limit latency.
 const base::Feature kDirectCompositionLowLatencyPresentation{
     "DirectCompositionLowLatencyPresentation",
@@ -200,11 +196,6 @@
 const base::Feature kDirectCompositionPreferNV12Overlays{
     "DirectCompositionPreferNV12Overlays", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Use per-present event queries to issue presentation feedback to clients.
-// Also needs DirectCompositionGpuVSync.
-const base::Feature kDirectCompositionPresentationFeedback{
-    "DirectCompositionPresentationFeedback", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Allow overlay swapchain to present on all GPUs even if they only support
 // software overlays.
 const base::Feature kDirectCompositionSoftwareOverlays{
diff --git a/ui/gl/vsync_observer.h b/ui/gl/vsync_observer.h
index 5d0fe964..7f7b115 100644
--- a/ui/gl/vsync_observer.h
+++ b/ui/gl/vsync_observer.h
@@ -5,6 +5,8 @@
 #ifndef UI_GL_VSYNC_OBSERVER_H_
 #define UI_GL_VSYNC_OBSERVER_H_
 
+#include "base/time/time.h"
+
 namespace gl {
 class GL_EXPORT VSyncObserver {
  public:
diff --git a/ui/gl/vsync_thread_win.h b/ui/gl/vsync_thread_win.h
index e3d65f1..fd516d12 100644
--- a/ui/gl/vsync_thread_win.h
+++ b/ui/gl/vsync_thread_win.h
@@ -36,6 +36,8 @@
   void AddObserver(VSyncObserver* obs);
   void RemoveObserver(VSyncObserver* obs);
 
+  gfx::VSyncProvider* vsync_provider() { return &vsync_provider_; }
+
  private:
   friend struct base::DefaultSingletonTraits<VSyncThreadWin>;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_device.cc b/ui/ozone/platform/wayland/host/wayland_data_device.cc
index f80738e5..8f4b62f 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_device.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_device.cc
@@ -109,14 +109,20 @@
                                 wl_fixed_t x,
                                 wl_fixed_t y,
                                 wl_data_offer* offer) {
+  auto* self = static_cast<WaylandDataDevice*>(data);
   WaylandWindow* window = wl::RootWindowFromWlSurface(surface);
+
+  // During Chrome's tab dragging, when a browser window is quickly snapped in
+  // and out, it might get destroyed before the wl_data_device::enter event is
+  // processed for a drag offer. If this happens, |window| will be null here, so
+  // destroy |new_offer_| here, as some compositors assume it. Such behavior has
+  // been observed in Exosphere compositor, for example.
   if (!window) {
-    LOG(ERROR) << "Failed to get window.";
+    self->new_offer_.reset();
+    VLOG(1) << "Failed to get window.";
     return;
   }
 
-  auto* self = static_cast<WaylandDataDevice*>(data);
-
   // Null |drag_delegate_| here means that the DND session has been initiated by
   // an external application. In this case, use the default data drag delegate.
   if (!self->drag_delegate_)
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc
index bad1730e..036d1b1 100644
--- a/ui/views/controls/menu/menu_controller.cc
+++ b/ui/views/controls/menu/menu_controller.cc
@@ -1542,7 +1542,7 @@
 // On Mac, treat space the same as return.
 #if !defined(OS_APPLE)
     case ui::VKEY_SPACE:
-      SendAcceleratorToHotTrackedView();
+      SendAcceleratorToHotTrackedView(event.flags());
       break;
 #endif
 
@@ -1574,7 +1574,7 @@
             OpenSubmenuChangeSelectionIfCan();
         } else {
           handled_key_code = true;
-          if (!SendAcceleratorToHotTrackedView() &&
+          if (!SendAcceleratorToHotTrackedView(event.flags()) &&
               pending_state_.item->GetEnabled()) {
             Accept(pending_state_.item, event.flags());
           }
@@ -1654,13 +1654,13 @@
   CHECK(!IsInObserverList());
 }
 
-bool MenuController::SendAcceleratorToHotTrackedView() {
+bool MenuController::SendAcceleratorToHotTrackedView(int event_flags) {
   Button* hot_view = GetFirstHotTrackedView(pending_state_.item);
   if (!hot_view)
     return false;
 
   base::WeakPtr<MenuController> this_ref = AsWeakPtr();
-  ui::Accelerator accelerator(ui::VKEY_RETURN, ui::EF_NONE);
+  ui::Accelerator accelerator(ui::VKEY_RETURN, event_flags);
   hot_view->AcceleratorPressed(accelerator);
   // An accelerator may have canceled the menu after activation.
   if (this_ref) {
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h
index 9da3b74..6908150c 100644
--- a/ui/views/controls/menu/menu_controller.h
+++ b/ui/views/controls/menu/menu_controller.h
@@ -362,8 +362,9 @@
   ~MenuController() override;
 
   // Invokes AcceleratorPressed() on the hot tracked view if there is one.
-  // Returns true if AcceleratorPressed() was invoked.
-  bool SendAcceleratorToHotTrackedView();
+  // Returns true if AcceleratorPressed() was invoked. |event_flags| is the
+  // flags of the received key event.
+  bool SendAcceleratorToHotTrackedView(int event_flags);
 
   void UpdateInitialLocation(const gfx::Rect& bounds,
                              MenuAnchorPosition position,